|
|
|||||||||
|
|||||||||
| |||||||||
|
|
|
| |||||||||
![]() |
|
|
«
Previous Thread
|
Next Thread
»
|
Thread Tools | Search this Thread | Rate Thread | Display Modes |
|
|
|
Stop making mediocre tutorials.The best tutorials are video! Camtasia Studio makes it easy to create engaging, buzz-building screen videos at any size, in any popular format. Download the free trial!
|
|
#1
|
||||
|
||||
|
Reading and writing files
Hi all,
Im trying to write and read to a random access file in my c program, Im pretty new to the game so need a simple solution. Ive written to my file in the following way: /* Write the data to the disk */ fp = fopen("A:vehicles.raf", "a"); fwrite(&theVehicle, sizeof(theVehicle), 1, fp); fclose(fp); theVehicle is a structure that holds: char registration[10] char make[20] char model[20] int insuranceCat I can write to the file fine, no problem, but how to I make it drop to a new line, so I can do a search for new lines later on? If I keep appending the new record onto the last, then it doesn't let me enter any more than 3 vehicle details for some reason. Also, when I look in the file, I find I get loads of characters appear that weren't typed in. For example: I type in as the model: Mondeo The rest of the elements in the array sometimes come out as unrecognisable characters, do I need to pad out the array with " ", and if so, how? The next model I type in is: 25 Then I look at the .raf file and it says '25 deo' Im assuming that its taking a bit of 'Mondeo' and sticking it on the end, how do I prevent this? Finally, my problem is reading the files back, Ive read about fseek() but dont really know how to use it, Im trying to read one record back at a time, not the whole lot, as I want to perform matching searches on it. I really appreciate any feedback and time you spend answering my questions. Regards, Mike. |
|
#2
|
|||||
|
|||||
|
Quote:
What do you mean by "drop to a new line"? Do you mean that once you have entered one car and written it to the file, that you want to have it ready to accept the entry of another car? That would be up to the program itself. E.g., I would have separate functions: 1. a function that initializes the data structure and sets up a new form on the display (don't know what OS or type of display you're doing, but this functionality should not depend on those details). 2. a function that processes the form; ie, that accepts input from the user, updates the form on the display, updates the data structure (might want to hold this one off until you exit the form, keeping the entered values in local variables), and accepts user-entered commands to accept the form or cancel out. If you don't update the data structure until you exit the form, you would do that when the user accepts the form, but of course not if he cancels it. 3. a function to write the data structure to the file to a specified record number. This function would interpret a special record number as meaning "append" (eg, -1 or MAX_INT), perform an open, write the record as you describe, and close the file. Of course, it would use fseek() to position the file pointer. BTW, I think you would also want to make this a binary file. I'm also not sure what you mean by "do a search for new lines later on". And since you only specify 3 vehicle details in your struct, I don't see why you would expect to be able to enter more than three. Quote:
Just basic C character strings. In C, a character string can be any length, but must always be terminated with a NULL, written as '\0' (ASCII code zero). You just have to be sure that you declare a char array that is large enough to hold your longest string plus one for the NULL. So your registration array of [10] can hold a string of up to nine characters and your make and model arrays of [20] can hold strings of up to 19 characters. Because of the null-terminator, anything else in your char array after the NULL doesn't matter at all. All that your program will pay any attention to will be what starts at the beginning of the array and ends right before the NULL. The rest doesn't matter. Get a hex dump of your file and take a look at the actual character in the middle of "25 deo"; you should find that it is a 00, which is the null-terminator. None of your code will ever see that "deo", so it doesn't matter. The same applies for those garbage characters you sometimes see. Your data structure, theVehicle, was declared within a function, wasn't it? This gets into C storage classes, but the upshot is that a global variable or a static variable goes into static storage, which would be in the Data Segment of an Intel machine (eg, in DOS or Windows). Static variables are usually automatically initialized to all zeros at the start of the program (but don't ever count on it), unless you explicitly initialize them to something yourself. But variables declared within a function are of the auto storage class and are stored on the stack (eg, in Intel's Stack Segment). Auto variables are not initialized unless you do initialize them explicitly yourself. Otherwise, they just contain whatever was in memory before, AKA "garbage". As long as you are going to store something into every field of theVehicle, it doesn't matter what garbage is in it to begin with nor what garbage remains after the NULL in each array. But if there's any chance of reading that data before you write something to it, then you should initialize it explicitly; eg: Code:
Vehicles theVehicle = {"","","",0}; // just making all strings blank
An interesting security note, BTW: In DOS and on Windows, disk space is allocated in blocks that were called "clusters". If the clusters are 8K each, then for every file, even if it's only one byte long, at least 8K is allocated. And when a file gets longer than its cluster size, another cluster is allocated to it, and so on. When you delete a file, its clusters are returned to the free list with their contents unchanged. So when one of those clusters is reallocated to a new file and that new file does not completely use that cluster, then the old data is still there. Even though that old data cannot normally be accessed (like the remaining characters in a char array after the NULL), there have long been forensics tools that can read that old data. And for just as long, there have been security tools to delete a file by first overwriting all of its data so that none remains. Quote:
You use fseek() to position the file pointer, then you use fread to read starting at that point: Code:
fseek(fp,rec_no*sizeof(Vehicles), SEEK_SET); // from beginning of file, first record is #0 bytesread = fread(&aVehicle, sizeof(Vehicles), 1, fp); // read one record Please note that fread() advances the file pointer, so after the fread() the file pointer is now pointing to the next record. You can verify this with ftell(). Hope that helps. Last edited by dwise1_aol : May 11th, 2003 at 12:12 PM. |
|
#3
|
||||
|
||||
|
Hi again,
Wow, thanks for the lengthy answer! I feel so stupid for saying this, but Im still stuck ![]() Ive managed to incorporate the fseek into the search function ok, and also done so for the adding (but not sure it is entirely correct). I got a problem though when I go to add the fourth record. I add the first 3 fine, and the error check works when I type in a registration number that has been entered before, but when I go to add a fourth vehicle, the error message "[REGISTRATION NUMBER EXISTS]" appears no matter if it does not. I have a single line in my raf file that has the following: Code:
t398gut Ford Mondeo 6 w145hbf Rover 25 deo 7 v654fre Rover 75 deo 8 Thats why I was asking how to make it drop to the next line, Im assuming that its adding up to the end of the third record, then returning to the beginning of the first line when checking against the fourth vehicle registration. I have attached a more lengthy code listing below to show you if Im doing anything wrong that I didn't explain in the first. I may have other things wrong with my code or inappropriate, but Im really just looking for an answer on how to write to the file and read it back (record by record) I really appreciate any response. Mike. Code:
=======================================
VARIABLES
=======================================
int validateRegistration(char Reg[10]);
int searchForRegistration(char sReg[10]);
/* A record contains the reg, make, model and insurance of a vehicle */
typedef struct{
char registration[10];
char make[20];
char model[20];
int insuranceGroup;
} vehicles;
/* Each vehicle can be manipulated globally */
vehicles theVehicle;
vehicles tmpVehicle;
/* Create a file pointer */
FILE *fp;
=======================================
ADDING THE VEHICLE DATA
=======================================
printf("[ADD INFORMATION]\n\n");
/* WOULD THE USER LIKE TO ADD ANOTHER AFTER? (LOOP) */
regInvalid = 1;
/* Add registration */
while(regInvalid == 1){
printf("Please enter the vehicles registration number\n");
printf(":> ");
scanf("%s", &theVehicle.registration);
/* Validate registration */
regInvalid = (validateRegistration(theVehicle.registration) == 1) ? 0 : 1;
if(regInvalid == 1){
printf("\n[REGISTRATION NUMBER INVALID]\n\n");
}
else{
/* Check for duplicate registration number */
regInvalid = (searchForRegistration(theVehicle.registration) == 0) ? 0 : 1;
if(regInvalid == 1) printf("\n[REGISTRATION NUMBER EXISTS]\n\n");
}
}
/* Add Make */
printf("Please enter the vehicles make\n");
printf(":> ");
scanf("%s", &theVehicle.make);
/* Add model */
printf("Please enter the vehicles model\n");
printf(":> ");
scanf("%s", &theVehicle.model);
/* Add insurance group */
printf("Please enter the insurance group for this vehicle\n");
printf(":> ");
scanf("%s", &theVehicle.insuranceGroup);
/* Write the data to the disk */
fp = fopen("A:vehicles.raf", "a");
fseek(fp, ftell(fp) +1, SEEK_END);
fwrite(&theVehicle, sizeof(theVehicle), 1, fp);
fclose(fp);
/* Inform user of add, then display menu */
printf("\n[RECORD ADDED]\n\n");
displayMenu = 1;
=======================================
READING THE FILE
=======================================
int searchForRegistration(char sReg[10]){
/* Declare variables */
int regCount, rowNum;
int regFound;
/* Initiate status of find and record position */
regFound = 0;
rowNum = 0;
/* Open the file, perform search on all records */
fp = fopen("A:Vehicles.raf", "r");
while(! feof(fp)){
fseek(fp, rowNum *sizeof(vehicles), SEEK_SET);
fread(&tmpVehicle, sizeof(vehicles), 1, fp);
for(regCount = 0; regCount < sizeof(tmpVehicle.registration); regCount++){
if(sReg[regCount] == tmpVehicle.registration[regCount]){
regFound += 1;
}
else{
regFound = regFound;
}
}
rowNum += 1;
}
fclose(fp);
/* Return the status of our search */
if(regFound >= 10){
return 1;
}
else{
return 0;
}
}
|
|
#4
|
||||
|
||||
|
In this code fragment for adding a vehicle:
Code:
/* Write the data to the disk */
fp = fopen("A:vehicles.raf", "a");
fseek(fp, ftell(fp) +1, SEEK_END);
fwrite(&theVehicle, sizeof(theVehicle), 1, fp);
fclose(fp);
You have already opened the file for appending, so the file pointer is already in the correct position. However, your fseek is wrong, which might be causing your problem by writing to the wrong location. The origin constants of SEEK_SET and SEEKCUR will add the offset you provide to the beginning of the file or to the current file position respectively. But since there's nothing after the end of the file, SEEK_END will subtract the offset. Also, fseek and ftell offsets are in bytes, so to move the pointer by n records, you would need to use an offset of n*sizeof(theVehicle). Adding one to the current file pointer would only move it by one byte, not by one record. In reading the help file on ftell and fseek, I found references to possible problems in using ftell before an I/O operation has occurred; from the Visual C++1.52 help file on ftell(): Quote:
This might do more to explain why you can't seem to add more records after a point. And if you examine a hex dump of your file, you should be able to see just where the latest record is actually being written. Or output the value of ftell() at strategic points. |
![]() |
| Viewing: Dev Shed Forums > Programming Languages > C Programming > Reading and writing files |
| Thread Tools | Search this Thread |
| Display Modes | Rate This Thread |
|
|
|
|