I need to edit each byte in an application, and I need to store it somewhere. First I used char* or unsigned char*, but when I read a more complex files which contains zero's the whole thing doesn't work any more (zero equals '\0' a.k.a end of string). What should I use instead?
unsigned char * is the proper data type, you simply need to store the number of bytes you have in a separate variable.
Always remember that you are dealing with bytes, not strings/characters - so you cannot use any string functions as they expect terminated strings.
If you want the length, use your variable that contains it
If you want to compare bytes, use memcmp instead of strcmp
if you want to load a file which has zeros inside (binary file) just use stat() on the file to get the size of the file and write it into the array with a loop till the indexer has the same value with the size of the file minus 1 or use this method:
struct stat fistat;
//get the size of the file
if(stat("filename",&fistat)<0) {
printf("file not found\n");
return 1;
}
// open the file
FILE* file = fopen("filename","r");
if (!file){
printf("can't open file\n");
return 1;
}
unsigned char buff[fistat.st_size];
// write the file to buffer
fread(buff,fistat.st_size,1,file);
fclose(file);
this way you have your file in the buff which has the size fistat.st_size.
Related
I'm working on a project using UDP protocol to transfer a file, but when I use strcpy() to copy a buffer into another string, it always missing some characters.
The simple idea is that:
I defined a struct:
struct frame{
int kind;//transmission(0) or retransmission(1)
int seq;
int ack;
char info[256];
};
Then I use fread to get the content of a text file into the buffer:
char buffer[256] = {0};
fread(buffer, 256, 1, fp);//read file: 256 byte
struct frame currFrame;
currFrame.ack = 0;
bzero(currFrame.info, 256);
strcpy(currFrame.info, buffer); //store the content to transfer
printf("%s\n", buffer);
printf("%s\n", currFrame.info);
The code above is in a for loop because i read file multiple times.
when I use printf(), half time, the result is right. But half time, they are different(like missing some characters in the head). How can I fix this?
The output is attached(The above is buffer, which is right):
The strcpy function is only for strings. To copy arbitrary data, use memcpy. Also, the %s format specifier is only for strings. Functions like fread read arbitrary binary data and don't try to form strings.
Also, you called fread in such a way that it won't tell you how many bytes it actually read. Unless you're positive you're always going to read exactly 256 bytes, that isn't smart. Instead, set the second parameter of fread to 1 and use the third parameter to set the maximum number of bytes to read. And don't ignore the return value -- that's how you know how many bytes it was actually able to read.
I'm porting some code on an embedded platform that uses a C-like API. The original code uses fscanf() to read and parse data from files. Unfortunately on my API I don't have a fscanf() equivalent, so prior to the actual porting I'm trying to obtain the same behavior of fscanf() using fread() and vsscanf() (which I do have). I also have the equivalent of fseek() and ftell().
EDIT: please keep in mind that the access to the embedded filesystem is very limited (fread - fseek - ftell - fgetc - fgets), so I need a solution that works with strings in memory rather than accessing the file in some other way.
The code looks something like this:
int main()
{
[...] /* variable declarations and definitions */
do
{
read = wrapped_fscanf(pFile, "%d %s", &val, str);
} while (read == 2);
fclose(pFile);
return 0;
}
int wrapped_fscanf(FILE *f, const char *template, ...)
{
va_list args;
va_start(args, template);
char tmpstr[50];
fread(tmpstr, sizeof(char), sizeof(tmpstr), f);
int ret = vsscanf(tmpstr, template, args);
long offset = /* ??? */
fseek(f, offset, SEEK_CUR);
va_end(args);
return ret;
}
The problem is that fscanf() moves the pointer to the position in the file stream at the end of the match, whereas with fread() I'm reading a fixed amount of data (in this case 50 bytes) and I should find a way to move the pointer back to the end of the matched string.
Let's assume that the 50-char string I read from the file is the following:
12 bar 13 foo 56789012345678901234567890123456789
fscanf() would match the int 12 , the string bar and the pointer would point right after the "r" in "bar" so I can call it again and read 13 foo
On the other hand fread() puts the pointer after the last char in the 50-element sequence, which is wrong: I still have to read 13 foo but if I call wrapped_fscanf() again the pointer is in the 51st position.
I have to use fseek() to roll back to the end of the first match, but how do I do that? How do I calculate the value of offset ?
vsscanf() returns the number of matches, not the length of the string and I have no way of knowing how many whitespace charachters separate the elements of the match (or do I?)
I.e. I get the same outputs( {var,str,read} == {9,"xyz",2} ) with
9 xyz
and
9 xyz
Is there some trick that I'm not aware of or do I have to find another solution other than wrapping fscanf() with fread() vsscanf() ftell() and fseek()?
Thank you
Supposing that your vsscanf() implementation supports it, your substitute for fscanf() can append a %n field descriptor to the end of the provided format. As long as there is no failure prior to vsscanf() reaching that field, it will store the number of characters consumed up to that point in the corresponding argument. You could then use that result to reposition the stream appropriately. That would require a bit of varargs wrangling and probably some macro assistance, but I think it could be made to work.
You will need some intermediary buffering code, that will grab chunks of data (using fread), and scan your buffer for the pattern. if the pattern is found, truncate the buffer, if the pattern is not found, append some more data. this is effectively what fscanf will do.
I want to append elements into a file line by line, not the end of the file.
I wrote this code, but the result was that I could only append elements at the end of the file.
#include <stdio.h>
#include <stdio.h>
int main(void)
{
static const char filename[] = "m.txt";
FILE *file = fopen(filename, "r+a");
char *a = "ok";
if (file != NULL)
{
char line[128]; /* or other suitable maximum line size */
while (fgets(line, sizeof line, file) != NULL) /* read a line */
{
fputs(a, file); /* write the line */
}
fclose(file);
}
else
{
perror(filename); /* why didn't the file open? */
}
return 0;
}
Some answers have mentioned buffer.
I am a little confused with the buffer here. Does it mean I have to read more than one line into memory and then modify them? And is buffer the same as BufferedReader class in Java?
You need to read each line one at a time, modify it as you see fit, and then rewrite the whole line to a new file. Then when you have read the whole file you rename the new file as the old file.
Or you read the whole file into memory, for example into an array, one line per element of the array, modify the lines, and overwrite the contents of the file.
The problem with modifying a variable-length text file is that you nee4d to shift all data after the insertion point, which is not easy to do in a file. That's why it's easier to read the whole file into memory and do the modifications there, or use a temporary file that you then rename.
Files are not stored as an array of lines you can append to and manipulate at will, they are one big chunk of data you interpret. So if you were to do such a thing, you'd overwrite the rest of the file that follows your current line.
What you have to do is re-write at least the entire rest of the file whenever you do this. You can do that easily using a buffer.
Lines in files are just formatting and logical points marked by the newline character.
I got some code and I want improve it to find and replace bytes in file
so
I want to find all origbytes in FILE and then replace it with newbytes
then save file, I know how to open, write and save, but hot I can find bytes in char?
FILE* file;
file = fopen("/Users/Awesome/Desktop/test", "r+b");
int size = sizeof(file)+1;
char bytes [size];
fgets(bytes, size, file);
for (int i=0; i<size; i++){
char origbytes [] = {0x00, 0x00};
char newbytes [] = {0x11, 0x11};
if (strcmp(bytes[i], origbytes)) //Here the problem
{
fseek(file, i, SEEK_SET);
fwrite(newbytes, sizeof(newbytes), 1, file);
}
}
fclose(file);
strcmp() is for string compare and not character compare. Two characters can be compared directly
if ( bytes[i] == origbytes[something] )
Also you you should not apply sizeof() on a file pointer to determine file size. You should seek to the end of file using fseek and then query ftell except for binary files. For binary files, use something like fstat
One more thing to note is that fgets returns much before the EOF if it sees a newline. Hence in your code, you may not read entire file contents even after doing the changes that we suggested. You need to use fread appropriately
Strings are null terminated in the C standard library. Your search data is effectively a zero length string. You want memcmp instead.
memcmp (&bytes [i], origBytes, 2)
Firstly sizeof(file) + 1 just returns you the size of a pointer + 1. I don't think you need this for the size of the file. Use this: How do you determine the size of a file in C?
Then since you compare bytes (more or less smae as char) you simply compare using =
you can use fseek and then ftell functions to get the file size, not sizeof.
The user should input some file names in the command line and the program will read each file name from argv[] array. I have to perform error checking etc.
I want to read each filename. For example, if argv[2] is 'myfile.txt', the program should read the content of 'myfile.txt' and store value in char buffer[BUFSIZ] and then write the content of buffer into another file.
However before the content is written, the program should also write the name of the file and the size. Such that the file can be easily extracted later. A bit like the tar function.
The file I write the content of buffer, depending on the number of files added by user, should be a string like:
myfile.txt256Thisisfilecontentmyfile2.txt156Thisisfile2content..............
My question is
1) How do I write value of argv[2] into file using write() statement, as having problems writing char array, what should I put as (sizeof(?)) inside write(). see below as I don't know the length of the file name entered by the user.
2) Do I use the '&' to write an integer value into file after name, for example write 4 bytes after file name for the size of file
Here is the code I have written,
char buffer[BUFSIZ];
int numfiles=5; //say this is no of files user entered at command
open(file.....
lseek(fdout, 0, SEEK_SET); //start begging of file and move along each file some for loop
for(i=0-; ......
//for each file write filename,filesize,data....filename,filesize,data......
int bytesread=read(argv[i],buffer,sizeof(buffer));
write(outputfile, argv[i], sizeof(argv)); //write filename size of enough to store value of filename
write(outputfile, &bytesread, sizeof(bytesread));
write(outputfile, buffer, sizeof(buffer));
But the code is not working as I expected.
Any suggestions?
Since argv consists of null-terminated arrays, the length you can write is strlen(argv[2])+1 to write both the argument and null terminator:
size_t sz = strlen (argv[2]);
write (fd, argv[2], sz + 1);
Alternatively, if you want the length followed by the characters, you can write the size_t itself returned from strlen followed by that many characters.
size_t sz = strlen (argv[2]);
write (fd, &sz, sizeof (size_t));
write (fd, argv[2], sz);
You probably also need to write the length of the file as well so that you can locate the next file when reading it back.
1., You can write the string the following way:
size_t size = strlen(string);
write(fd, string, size);
However, most of the time it's not this simple: you will need the size of the string so you'll know how much you need to read. So you should write the string size too.
2., An integer can be written the following way:
write(fd, &integer, sizeof(integer));
This is simple, but if you plan to use the file on different architectures, you'll need to deal with endianness too.
It sounds like your best bet is to use a binary format. In your example, is the file called myfile.txt with a content length of 256, or myfile.txt2 with a content length of 56, or myfile.txt25 with a content length of 6? There's no way to distinguish between the end of the filename and the start of the content length field. Similarly there is no way to distinguish between the end of the content length and the start of the content. If you must use a text format, fixed width fields will help with this. I.e. 32 characters of filename followed by 6 digits of content length. But binary format is more efficient.
You get the filename length using strlen(), don't use sizeof(argv) as you will get completely the wrong result. sizeof(argv[i]) will also give the wrong result.
So write 4 bytes of filename length followed by the filename then 4 bytes of content length followed by the content.
If you want the format to be portable you need to be aware of byte order issues.
Lastly, if the file won't all fit in your buffer then you are stuffed. You need to get the size of the file you are reading to write it to your output file first, and then make sure you read that number of bytes from the first file into the second file. There are various techniques to do this.
thanks for replies guys,
I decided not to use (size_t) structure instead just assigned (int) and (char) types so I know exact value of bytes to read() out. ie I know start at beggining of file and read 4 bytes(int) to get value of lenght of filename, which I use as size in next read()
So, when I am writing (copying file exactly with same name) users inputted file to the output file (copied file) I writing it in long string, without spaces obviously just to make it readable here,
filenamesize filename filecontentsize filecontent
ie 10 myfile.txt 5 hello
So when come to reading that data out I start at begining of file using lseek() and I know the first 4 bytes are (int) which is lenght of filename so I put that into value int namelen using the read function.
My problem is I want to use that value read for the filenamesize(first 4 bytes) to declare my array to store filename with the right lenght. How do I put this array into read() so the read stores value inside that char array specified, see below please
int namelen; //value read from first 4 bytes of file lenght of filename to go in nxt read()
char filename[namelen];
read(fd, filename[namelen], namelen);//filename should have 'myfile.txt' if user entered that filename
So my question is once I read that first 4 bytes from file giving me lenght of filename stored in namelen, I then want to read namelen amount of bytes to give me the filename of originally file so I can create copied file inside directory?
Thanks