Writing to File with Offset - c

I'm trying to write a simple block of code that writes the contents of an array to a position in a file. The file is a simple, text only file. It seems to do everything write, but file contents end up in hex (with a bunch of zeroes at the beginning). I'm using the following:
FILE * fp; // file to write to
void fwritel(long offset, char * data) {
fp = fopen(filename, "w");
fseek(fp, offset, SEEK_SET);
fwrite(data, 1, strlen(data) - 1, fp);
fclose(fp);
}
I've also used a variation of pwrite that didn't work: pwrite(fp, data, strlen(data) - 1, offset); The code I'm looking for would write data at position offset only modifying the file from offset to offset + strlen(data).

This is a multiple part fix:
Joachim Pilebord is right. Opening the file using fopen(file, "w") will destroy the contents of the file. So each time it would open the file, zero the file, then write the new contents.
M Oehm was also correct, the new content would be padded with zeros - thus Sublime treated it as hex.
So, opening the file once, somewhere at the beginning of the program, using only
fseek(fp, offset, SEEK_SET);
fwrite(data, 1, strlen(data), fp);
and closing the file somewhere near the end of the program produces the correct output. Using fputc(' ') would work but you'd need to make sure I'm not replacing characters that you need (i.e. previously placed data in those parts of the file).

Related

Writing to binary files at offset zeroes all previous bytes

I'm trying to write to a new file with 'wb' mode at given offset using function owrite provided below, but every time it overwrite all bytes before the offset.
Using windows 10, visual studio 2019 16.0.3.
Offset is positive number and outside file bounds (since it's a new file).
count == 64000 == size of buf.
I've tried to use lseek/_lseek write/_write (with fileno) but ended up with similar result. owrite don't return -1, also checked output of fwrite and everything seems fine. What is the right way to perform this operation?
int owrite(FILE* fd, char* buf, size_t count, int offset)
{
if (fseek(fd, offset, SEEK_SET) != 0) {
return -1;
}
fwrite((char*)buf, sizeof(char), count, fd);
fseek(fd, 0, SEEK_SET);
return 0;
}
Also here is function that calls owrite:
void insert_chunk(byte* buffer, int len, char* filename, long offset)
{
FILE* builded_file = fopen(filename, "wb");
owrite(builded_file, buffer, len, offset);
fclose(builded_file);
}
//byte is unsigned char
You are telling it to discard existing contents when you open the file. You want "r+", not "w" (or, "r+b" in your case).
From http://www.cplusplus.com/reference/cstdio/fopen/:
"w" write: Create an empty file for output operations. If a file with the same name already exists, its contents are discarded and the file is treated as a new empty file.
Note that "r+" only works if the file already exists. If you don't know whether the file exists, you may need to check that first, and open with "w" or "w+" if it doesn't exist.
If you really want to add to the end of the file, and not to an offset in the middle, you could use "a" or "a+", which will create the file if it does not exist.

Reading a text file full with null characters and texts using fread

I am trying to design a small file system.
I have created a text file to store the files data in.
int kufs_create_disk(char* disk_name, int disk_size){
FILE* file_ptr = fopen(disk_name, "w");
if (file_ptr == NULL)
return -1;
fseek (file_ptr, disk_size * 1024-1, SEEK_SET);
fwrite("", 1, sizeof(char), file_ptr); // to make a size for the file
fclose(file_ptr);
DiskName=disk_name;
return 0;
}
After writing to the file I get a file with the size I determine when I call the function.
kufs_create_disk("test.txt", 5);
which creates a file with size of 5kbs with '\0' to fill this file to the size.
I have created another function to write to this file in different places of the file which works just fine and I won't paste the code for simplicity.
When I try to read from the file using fread(), I'm not getting all the data I have written into the memory; rather I get just some of the data.
My read implementation would be:
int kufs_read(int fd, void* buf, int n){
FILE *file_ptr= fopen("test.txt","a+");
fseek (file_ptr, FAT[fd].position, SEEK_SET); //where FAT[fd].position is where I want to start my read and fd is for indexing purposes
fread(buf, 1, n, file_ptr); //n is the number of bytes to be read
FAT[fd].position = FAT[fd].position + n;
}
The thing is the file reads some of the characters written and doesn't read the rest. I did a little test by looping all over the file and checking whether every thing is being read and fread reads every thing but in the buf I only get some of the characters I've written.
The text file looks something like this:
0\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00written string1written string2 0\00\00\00\00\00\00\00\00\00\00\00\000\00\00\00\00\00\00\00\00\00\00\00\00writtenstring 3 \00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00
I get writtenstring1 and writtenstring2 in the buffer but I don't get writtenstring 3 for example.
Can you explain why?

checking a file from a certain offset without reading the entire file

what I want to do is open a file(which is huge) and read from a certain point of bytes to an offset.
in c# this can be done with:
File.ReadAllBytes(file).Skip(50).Take(10).ToArray();
the problem with this is that it reads the entire file but since my files can be huges this also takes a long time. is there a way to read parts of a file similiar to this method but WITHOUT reading the entire file? In c preferably
Yes, use the fseek() standard library function to move ("seek") to the desired position:
FILE *in = fopen("myfancyfile.dat", "rb");
if(fseek(in, 50, SEEK_SET) == 0)
{
char buf[10];
if(fread(buf, sizeof buf, 1, in) == 1)
{
/* got the data, process it here */
}
}
fclose(in);

How to make a variable return after exit in C

Okay so I have a program and it adds new entries to a structure to a .dat file. I know when appending it adds to the end of the list. This works fine. The problem I am having is that I have a tracking variable that keeps track of the length of the struct. I can bring back the items in the struct but how do I bring back the variable that is keeping track of the length. You can't find it's length either so I would have to bring back a variable. I was thinking leave the first line of the .dat file just for the tracking variable but I don't know if you can append just the first line.
Bellow is of course what I am using to add in items to my struct. Above it would be num ++ which means the length of the struct increased by one.
if ( pWrite != NULL ) {
fprintf(pWrite, "%s %s %s\n", info2[nume].first, info2[nume].last, info2[nume].number);
fclose(pWrite);
} else {
perror("The following error occurred");
exit(EXIT_FAILURE); //exit program with error
}
Not sure if I am leaving anything out. Any help would be great. Thanks!
Store an integer in the file which represents the amount of structs you have in the file.
[integer]xxxxxxxxxxxxxxxxxxxxxx
or
xxxxxxxxxxxxxxxxxxxxxx[integer]
In the both cases, updating would require the r+ flag when opening the file (→ fopen). Then, you can simply read and then overwrite the integer.
// This may not work - my C skills got worse over the time :)
FILE *f = fopen("test.dat", "r+");
fread(buffer, sizeof(int), 1, f);
fseek(f, 0, SEEK_START);
fwrite(buffer, sizeof(int), 1, f);
If the elements of the struct are of known length, then you can look at the file size and compute how many elements there must be. That is the easiest way to accomplish what you are asking.
EDIT After reading other attempted answers, and your comments, here is something that might work better for you - random file access. The following illustrates this:
FILE *fp;
int myCounter = -1;
fp = fopen("myFile.dat", "wb"); // want to write
fwrite(&myCounter, sizeof(int), 1, fp); // write size of -1 to start of file: "unknown count"
fprintf(fp, "Now I write something");
fseek(fp, 0, SEEK_SET); // point file to beginning
myCounter=1;
fwrite(&myCounter, sizeof(int), 1, fp); // write the new size: 1
fseek(fp, 0, SEEK_END); // back to the end of the file
fprintf(fp, "Here is something else");
... etc
It should be obvious how you can wrap this into a loop - note though that it would be slow to update the file counter on every write, since the disk will be "hunting" from one sector to another. So better write until you have no more to write, then update the counter at the start of the file with the fseek command. You do need to do the first write just to make sure you leave space. I chose to write -1 as this would indicate to the reading program "no valid size has been written". Usually good to put some error checking like that in your code...
If you haven't saved the variable's value somehow/somewhere (for example, written to a file), and can't recompute it from what you HAVE saved, its gone.

Copying a file in C with fwrite

I am new to C and was trying to write a program just to copy a file so that I could learn the basics of files. My code takes a file as input, figures out its length by subtracting its start from its end using fseek and ftell. Then, it uses fwrite to write, based on what I could get from its man page, ONE element of data, (END - START) elements long, to the stream pointed to by OUT, obtaining them from the location given by FI. The problem is, although it does produce "copy output," the file is not the same as the original. What am I doing wrong? I tried reading the input file into a variable and then writing from there, but that didn't help either. What am I doing wrong?
Thanks
int main(int argc, char* argv[])
{
FILE* fi = fopen(argv[1], "r"); //create the input file for reading
if (fi == NULL)
return 1; // check file exists
int start = ftell(fi); // get file start address
fseek(fi, 0, SEEK_END); // go to end of file
int end = ftell(fi); // get file end address
rewind(fi); // go back to file beginning
FILE* out = fopen("copy output", "w"); // create the output file for writing
fwrite(fi,end-start,1,out); // write the input file to the output file
}
Should this work?
{
FILE* out = fopen("copy output", "w");
int* buf = malloc(end-start); fread(buf,end-start,1,fi);
fwrite(buf,end-start,1,out);
}
This isn't how fwrite works.
To copy a file, you'd typically allocate a buffer, then use fread to read one buffer of data, followed by fwrite to write that data back out. Repeat until you've copied the entire file. Typical code is something on this general order:
#define SIZE (1024*1024)
char buffer[SIZE];
size_t bytes;
while (0 < (bytes = fread(buffer, 1, sizeof(buffer), infile)))
fwrite(buffer, 1, bytes, outfile);
The first parameter of fwrite is a pointer to the data to be written to the file not a FILE* to read from. You have to read the data from the first file into a buffer then write that buffer to the output file. http://www.cplusplus.com/reference/cstdio/fwrite/
Perhaps a look through an open-source copy tool in C would point you in the right direction.
Here is How It can be done:
Option 1: Dynamic "Array"
Nested Level: 0
// Variable Definition
char *cpArr;
FILE *fpSourceFile = fopen(<Your_Source_Path>, "rb");
FILE *fpTargetFile = fopen(<Your_Target_Path>, "wb");
// Code Section
// Get The Size Of bits Of The Source File
fseek(fpSourceFile, 0, SEEK_END); // Go To The End Of The File
cpArr = (char *)malloc(sizeof(*cpArr) * ftell(fpSourceFile)); // Create An Array At That Size
fseek(fpSourceFile, 0, SEEK_SET); // Return The Cursor To The Start
// Read From The Source File - "Copy"
fread(&cpArr, sizeof(cpArr), 1, fpSourceFile);
// Write To The Target File - "Paste"
fwrite(&cpArr, sizeof(cpArr), 1, fpTargetFile);
// Close The Files
fclose(fpSourceFile);
fclose(fpTargetFile);
// Free The Used Memory
free(cpArr);
Option 2: Char By Char
Nested Level: 1
// Variable Definition
char cTemp;
FILE *fpSourceFile = fopen(<Your_Source_Path>, "rb");
FILE *fpTargetFile = fopen(<Your_Target_Path>, "wb");
// Code Section
// Read From The Source File - "Copy"
while(fread(&cTemp, 1, 1, fpSourceFile) == 1)
{
// Write To The Target File - "Paste"
fwrite(&cTemp, 1, 1, fpTargetFile);
}
// Close The Files
fclose(fpSourceFile);
fclose(fpTargetFile);

Resources