How to read a file in Crystal? - file

I recently picked up on Crystal after being a Rubyist for a while, and I can't seem to find anything about the File class. I want to open and read a file, but it gives me an error.
file = File.open("ditto.txt")
file = file.read
tequila#tequila-pc:~/code$ crystal fileopen.cr
Error in fileopen.cr:2: wrong number of arguments for 'File#read' (given 0, expected 1)
Overloads are:
- IO::Buffered#read(slice : Bytes)
- IO#read(slice : Bytes)
file = file.read
^~~~

You're probably looking for IO#gets_to_end which reads the entire file as a String. But you might as well use File.read
file_content = File.read("ditto.txt")
IO#read is a more low-level method which allows to read pieces of an IO into a byte slice.

Related

Why would the read system call stop working halfway through a program?

I'm working on an assignment that involves creating files and manipulating characters within them using what the lecturer describes as "File and System I/O calls" in C.
Specifically, I am using open, creat, read, write, lseek, close, and unlink.
Without revealing too much and violating academic integrity, essentially the assignment just entails creating files, copying characters between them, changing the characters, etc.
All of this was going perfectly until a certain point of the program after which read just... Wouldn't work. It doesn't matter what file I am accessing, or what other calls I put before it- for instance, I have tried closing and re-opening a file before trying to read, writing before reading (worked perfectly, put the characters right at the file position the lseek intended), etc.
I have checked the returns of all previous commands, none are giving errors other than the read, which is giving me errorno 9. Having looked this up, it appears to refer to having an incorrect file descriptor, but this doesn't make sense to me as I can use the same fid for any other command. Using ls -l, I confirmed that I have read and write permission (groups and public do not, if that helps).
I am at a total loss of where to go troubleshooting from here, any help would be immensely appreciated. Here is the code snippet in question:
readStatus = lseek(WWWfid,500,0);
if (readStatus<0) {
printf("error with lseek");
return 0;
}
/*printf("Read status: %i\n", readStatus);/*DEBUG*/
writeStatus = write(WWWfid, "wtf", 3);
if (writeStatus<0) {
printf("error with write");
return 0;
}
readStatus = read(WWWfid, buffer, 26);
int errorNum = errno;
/*buffer[27] = '\0';*/
if (readStatus<0) {
printf("error with read before loop, error %i\n", errorNum);
return 0;
}
I can likely include more without invoking the wroth of my uni but I'd prefer not to- also seems likely to be irrelevant given that all proceeding code appears to be functioning correctly.
Thanks for reading, please let me know if you have any insight at all

How to read a very large dataset from an HDF5 file?

I've started learning HDF5 API very recently. Suppose that I'm going to read a very large vector (i.e. one-dimentional array) which is stored as a dataset in an HDF5 file. Its size N_SIZE is so large that malloc(N_SIZE) fails. So it seems to me that I have to read it chunk by chunk. Should I use H5Dread_chunk() here?
Yes, you will have to read the dataset chunk by chunk if it does not fit in main memory. Also, please note that your dataset must be created with a chunked storage layout. Then you can read one chunk at the time using hyperslabs (i.e. slices).
All these can be greatly simplified with HDFql. HDFql is a high-level language that alleviates you from the low-level details of handling HDF5 files.
As an example, you could do the following in C using HDFql:
// declare variables
char script[100];
int data[1024][1024];
int i;
// create a HDF5 file named 'my_file.h5' and use (i.e. open) it
hdfql_execute("CREATE AND USE FILE my_file.h5");
// create a three dimensional chunked dataset named 'my_dataset' (each chunk is 1 MB)
hdfql_execute("CREATE CHUNKED(1, 1024, 1024) DATASET my_dataset AS INT(100, 1024, 1024)");
// register variable 'data' for subsequent usage
hdfql_variable_register(data);
// loop 100 times (i.e. number of chunks that exists in dataset 'my_dataset')
for(i = 0; i < 100; i++)
{
// prepare script to read one chunk at the time using an hyperslab
sprintf(script, "SELECT FROM my_dataset(%d:::1) INTO MEMORY 0", i);
// execute script
hdfql_execute(script);
// call hypothetical function 'process' passing variable 'data' that contains the chunked data
process(data);
}
Additional examples on how to use HDFql in C can be found here.

Suppress messages from underlying C-function in R

In a script I often call the function Rcplex(), which prints "CPLEX environment opened" and "Closed CPLEX environment" to the console. Since the function is called rather frequently, it prints this very often, which is quite annoying. Is there a way to suppress this? I tried sink(), suppressWarnings/Messages or invisible(catch.output()) but none of these did the trick. I proceeded to check the code of Rcplex() and found where the printing to the console happens. Rcplex() calls an underlying C-function (Rcplex.c). In the code of rcplex.c I located the commands which cause the printing:
REprintf("CPLEX environment opened\n");
REprintf("Closed CPLEX environment\n");
Is there a way to capture the output from REprintf() so that it does not get printed to the R-console? One way would obviously be to mess around with the Rcplex.c file and delete the corresponding lines. However, this would not be a very clean solution, which is why I'm asking for another way to capture the output from C-functions.
You had problems using sink() and capture.output() normally because sink() does not redirect output from REprintf, as we see in comments from the source code for REprintf:
/* =========
* Printing:
* =========
*
* All printing in R is done via the functions Rprintf and REprintf
* or their (v) versions Rvprintf and REvprintf.
* These routines work exactly like (v)printf(3). Rprintf writes to
* ``standard output''. It is redirected by the sink() function,
* and is suitable for ordinary output. REprintf writes to
* ``standard error'' and is useful for error messages and warnings.
* It is not redirected by sink().
However, we can use type = "message" to deal with this; from help("capture.output"):
Messages sent to stderr() (including those from message, warning and
stop) are captured by type = "message". Note that this can be "unsafe" and should only be used with care.
First I make a C++ function with the same behavior you're dealing with:
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
NumericVector example_function(NumericVector x) {
REprintf("CPLEX environment opened\n");
REprintf("Closed CPLEX environment\n");
// As mentioned by Dirk Eddelbuettel in the comments,
// Rcpp::Rcerr goes into the same REprintf() stream:
Rcerr << "Some more stuff\n";
return x;
}
If I call it from R normally, I get:
example_function(42)
CPLEX environment opened
Closed CPLEX environment
Some more stuff
[1] 42
However, I could instead do this:
invisible(capture.output(example_function(42), type = "message"))
[1] 42
And while the output is is printed to the console, the message is not.
Warning
I would be remiss if I didn't mention the warning from the help file I quoted above:
Note that this can be "unsafe" and should only be used with care.
The reason is that this will eliminate all output from actual errors as well. Consider the following:
> log("A")
Error in log("A") : non-numeric argument to mathematical function
> invisible(capture.output(log("A"), type = "message"))
>
You may or may not want to therefore send the captured output to a text file in case you have to diagnose something that went wrong. For example:
invisible(capture.output(log("A"), type = "message", file = "example.txt"))
Then I don't have to see the message in the console, but if I need to check example.txt afterward, the message is there:
Error in log("A") : non-numeric argument to mathematical function

TStringList behavior with non ANSI files

In my application, when I want import a file, i use TStringList.
But, when someone export data from Excel, the file encoding is UCS-2 Little Endian, and TStringList can't read the data.
There is any way to validate this situation, identify the text encoding and send a warning to the user that the text provided is not compatible?
Just to be clear, the user will provide only plain text..letter and numbers, otherwise this, I must send the warning.
Unicode File without BOM is good. (TStringList can read it!)
ANSI file Too. (TStringList can read it!)
Even Unicode with BOM will be good, if there is a way to remove it. (TStringList can read it!, but with "i" ">>" and "reverse ?" characters, that belongs to BOM bytes)
I used the following function in Delphi 6 to detect Unicode BOMs.
const
//standard byte order marks (BOMs)
UTF8BOM: array [0..2] of AnsiChar = #$EF#$BB#$BF;
UTF16LittleEndianBOM: array [0..1] of AnsiChar = #$FF#$FE;
UTF16BigEndianBOM: array [0..1] of AnsiChar = #$FE#$FF;
UTF32LittleEndianBOM: array [0..3] of AnsiChar = #$FF#$FE#$00#$00;
UTF32BigEndianBOM: array [0..3] of AnsiChar = #$00#$00#$FE#$FF;
function FileHasUnicodeBOM(const FileName: string): Boolean;
var
Buffer: array [0..3] of AnsiChar;
Stream: TFileStream;
begin
Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); // Allow other programs read access at the same time.
Try
FillChar(Buffer, SizeOf(Buffer), $AA);//fill with characters that we are not expecting then...
Stream.Read(Buffer, SizeOf(Buffer)); //...read up to SizeOf(Buffer) bytes - there may not be enough
//use Read rather than ReadBuffer so the no exception is raised if we can't fill Buffer
Finally
FreeAndNil(Stream);
End;
Result := CompareMem(#UTF8BOM, #Buffer, SizeOf(UTF8BOM)) or
CompareMem(#UTF16LittleEndianBOM, #Buffer, SizeOf(UTF16LittleEndianBOM)) or
CompareMem(#UTF16BigEndianBOM, #Buffer, SizeOf(UTF16BigEndianBOM)) or
CompareMem(#UTF32LittleEndianBOM, #Buffer, SizeOf(UTF32LittleEndianBOM)) or
CompareMem(#UTF32BigEndianBOM, #Buffer, SizeOf(UTF32BigEndianBOM));
end;
This will detect all the standard BOMs. You could use it to block such files if that's the behaviour you want.
You state that Delphi 6 TStringList can load 16 bit encoded files if they do not have a BOM. Whilst that may be the case, you will find that, for characters in the ASCII range, every other character is #0. Which I guess is not what you want.
If you want to detect that text is Unicode for files without BOMs then you could use IsTextUnicode. However, it may give false positives. This is a situation where I suspect it is better to ask for forgiveness than permission.
Now, if I were you I would not actually try to block Unicode files. I would read them. Use the TNT Unicode library. The class you want is called TWideStringList.

SIC Assembler I/O

I've coded a SIC assembler and everything seems to be working fine except for the I/O aspect of it.
I've loaded the object code into memory (converted char format into machine representation), but when I call SICRun(); to execute the code, I get an error stating "devf1 cannot be found".
I know this is related to the input/output device instructions in the source code.
The c file states that it depends on external files, most notably, Dev[6]. Am I supposed to create this myself? My instructor did not give us any other files to work with. Any insight?
Example: TD OUTPUT ;TEST OUTPUT DEVICE
This directory contains the source code (source.asm), header file (sic.h) and the SIC simulator (sicengine.c)
From the sicengine.c source file it looks as though the devf1 (also dev2/dev3) file is expected to exist so this 'input device' can be read from (fopen is passed "r" as a parameter):
if (opcode == 216) { /* RD */
/* ... */
if ((Dev[Devcode] = fopen(SICFile[Devcode],"r")) == NULL) {
printf("cannot open file %s\n", SICFile[Devcode]);
exit(1);
}
The comment in the code about depending on file Dev[6] is ambiguous. It really means the names of the files in the Dev array, which are devf1, devf2 and devf3 (input devices) and devf04, devf05 and devf05 (output devices).
I would suggest creating files devf1, devf1 and devf3.

Resources