replace bytes in file c - c

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.

Related

Read txt file from standard input and store whole text into char array

Let me describe what I am trying to do.
Compile the source and run with an input text file
gcc main.c -o main
./main < text.txt
Then the text inside 'text.txt' should be stored into one single variable. I am not sure, but I think this should be as char array.
Ultimately, I want loop through each character of 'text.txt' with its index; in python it should be like as follows
i = 0
while i < len(string):
print(string[i])
if (~~~):
i -= 10(or some other numbers)
else:
i += 1
Several points to consider
i can be decremented and print again from the i-10th character.
The program doesn't know the length of the input text file.
I cannot specify file directory in the source; the input text must come through standard input in the terminal.
How can I write this in C?
The following was my try in C, didn't work though.
int main(){
char A;
short i;
scanf("%s", A);
printf("%s", A);
for (i=0; i < strlen(A); i++) {
printf("%c", A[i]);
}
return 0;
}
You can do it multiple ways, lets start by getting proper length of file.
FILE *f = fopen("textfile.txt", "rb");
fseek(f, 0, SEEK_END); // goes to the end of file
long fsize = ftell(f); // tells what position in bytes is
fclose (f)
f = fopen("textfile.txt", "r");
You noticed that I am using rb or read binary. thats because to get over the fact that if you use fseek() and ftell() in non binary mode you are getting into undefined behavior and results may differ between Windows machine and (*)nix machine.
Now how to read a text file into the string. There are multiple ways
using getc() not preferred
using fscanf() not preferred either, better than getc() in a way that it reads mutiple bytes at the time
using fgets() you can specify the size of the file you read thus avoiding buffer overflow.
Above is quick and dirty way of reading, without knowing what is your DE like (what OS, compiler etc) I could go into more details how to do it, but tnx to #Nail here is an article, you can read. You could use it and have flags for different OSs instead of using my method.

Alternatives of fopen, fread for reading from string?

I have a code which integrates with a certain library I cannot modify and reads from file. I need to turn it into reading from string instead of from file.
string str = "I now have the string from file.txt in memory";
// original code:
FILE *file = fopen("file.txt", "rb");
// ...
uint8_t buffer[128];
// ...
var->var1 = buffer;
// ...
var->var2 = fread(buffer, 1, 128, file);
// ...
So a simple question, what's an alternative for fread for reading from string into buffer?
Platform: Windows
If you don't require a FILE *, if you just need to copy counted characters from one buffer (or string) to another, that's what memcpy is for. For example, to a first approximation, you could replace
fread(buffer, 1, 128, file);
with
memcpy(buffer, str, 128);
Now, this will break pretty badly if str does not contain 128 characters. (If your file had less than 128 characters on it, fread would give you less than 128.) So a safer replacement would be
int n = 128;
if(strlen(str) < n) n = strlen(str);
memcpy(buffer, str, n);
There is a function that does precisely what you want: fmemopen. You hand it a pointer to an in-memory string buffer, and a "r" or "w" flag (just like fopen), and it gives you a regular old FILE * that you can read from or write to -- or, in your case, pass to a function that needs a FILE * to read from or write to.
It's available in glibc and therefore in virtually all versions of Linux. I think it's available in some versions of Unix. I don't seem to have it on my Mac. I'm afraid you'll probably have a hard time finding it for Windows.
If i understand your task correctly, you need to get information out of a string as if they would been written from a file. A very comfortable way to solve that is std::stringstream, if you are using C++.

Byte array in C with data from files with zeros inside

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.

c programming read() and write() content to file

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

Unexpected output copying file in C

In another question, the accepted answer shows a method for reading the contents of a file into memory.
I have been trying to use this method to read in the content of a text file and then copy it to a new file. When I write the contents of the buffer to the new file, however, there is always some extra garbage at the end of the file. Here is an example of my code:
inputFile = fopen("D:\\input.txt", "r");
outputFile = fopen("D:\\output.txt", "w");
if(inputFile)
{
//Get size of inputFile
fseek(inputFile, 0, SEEK_END);
inputFileLength = ftell(inputFile);
fseek(inputFile, 0, SEEK_SET);
//Allocate memory for inputBuffer
inputBuffer = malloc(inputFileLength);
if(inputBuffer)
{
fread (inputBuffer, 1, inputFileLength, inputFile);
}
fclose(inputFile);
if(inputBuffer)
{
fprintf(outputFile, "%s", inputBuffer);
}
//Cleanup
free(inputBuffer);
fclose(outputFile);
}
The output file always contains an exact copy of the input file, but then has the text "MPUTERNAM2" appended to the end. Can anyone shed some light as to why this might be happening?
You may be happier with
int numBytesRead = 0;
if(inputBuffer)
{
numBytesRead = fread (inputBuffer, 1, inputFileLength, inputFile);
}
fclose(inputFile);
if(inputBuffer)
{
fwrite( inputBuffer, 1, numBytesRead, outputFile );
}
It doesn't need a null-terminated string (and therefore will work properly on binary data containing zeroes)
Because you are writing the buffer as if it were a string. Strings end with a NULL, the file you read does not.
You could NULL terminate your string, but a better solution is to use fwrite() instead of fprintf(). This would also let you copy files that contain NULL characters.
Unless you know the input file will always be small, you might consider reading/writing in a loop so that you can copy files larger than memory.
You haven't allocated enough space for the terminating null character in your buffer (and you also forget to actually set it), so your fprintf is effectively overreading into some other memory. Your buffer is exactly the same size as the file, and is filled with its content, however, fprintf reads the parameter looking for the terminating null, which isn't there, until a couple of characters later where, coincidently, there is one.
EDIT
You're actually mixing two types of io, fread (which is paired with fwrite) and fprintf (which is paired with fscanf). You should probably be doing fwrite with the number of bytes to write; or conversely, use fscanf, which would null-terminate your string (although, this wouldn't allow nulls in your string).
Allocating memory to fit the file is actually quite a bad way of doing it, especially the way it's done here. If the malloc() fails, no data is written to the output file (and it fails silently). In other words, you can't copy files greater than a few gigabytes on a 32-bit platform due to the address space limitations.
It's actually far better to use a smaller memory chunk (allocated or on the stack) and read/write the file in chunks. The reads and writes will be buffered anyway and, as long as you make the chunks relatively large, the overhead of function calls to the C runtime libraries is minimal.
You should always copy files in binary mode as well, it's faster since there's no chance of translation.
Something like:
FILE *fin = fopen ("infile","rb"); // make sure you check these for NULL return
FILE *fout = fopen ("outfile","wb");
char buff[1000000]; // or malloc/check-null if you don't have much stack space.
while ((count = fread (buff, 1, sizeof(buff), fin)) > 0) {
// Check count == -1 and errno here.
fwrite (buff, 1, count, fout); // and check return value.
}
fclose (fout);
fclose (fin);
This is from memory but provides the general idea of how to do it. And you should always have copiuos error checking.
fprintf expects inputBuffer to be null-terminated, which it isn't. So it's reading past the end of inputBuffer and printing whatever's there (into your new file) until it finds a null character.
In this case you could malloc an extra byte and put a null as the last character in inputBuffer.
In addition to what other's have said: You should also open your files in binary-mode - otherwise, you might get unexpected results on Windows (or other non-POSIX systems).
You can use
fwrite (inputBuffer , 1 , inputFileLength , outputFile );
instead of fprintf, to avoid the zero-terminated string problem. It also "matches better" with fread :)
Try using fgets instead, it will add the null for you at the end of the string. Also as was said above you need one more space for the null terminator.
ie
The string "Davy" is represented as the array that contains D,a,v,y,\0 (without the commas). Basically your array needs to be at least sizeofstring + 1 to hold the null terminator. Also fread will not automatically add the terminator, which is why even if your file is way shorter than the maximum length you get garbage..
Note an alternative method for being lazy is just to use calloc which sets the string to 0. But still you should only fread inputFileLength-1 characters at most.

Resources