Trying to write to end of file, but overwriting instead - c++

Im using a microblaze soft processor on a Basys3 dev board. I am able to write a text file to an SD card but I am trying to write to the end of the file. Currently it overwrites anything that's in the file. Im using the DFATFS functions to do the writing. The Basys3 has a PMOD uSD reader attached.
I've tried using the fslseek function in DFATFS to move the file pointer to the end of file but it still writes to the beginning.
//the subroutine to print to the SD card
void SD(int32_t rando, int addr, int bit, int pc) {
DXSPISDVOL disk(XPAR_PMODSD_0_AXI_LITE_SPI_BASEADDR,
XPAR_PMODSD_0_AXI_LITE_SDCS_BASEADDR);
DFILE file;
int eof;
char printline[128];
sprintf(printline, "\nLFSR: %d ", rando);
// The drive to mount the SD volume to.
// Options are: "0:", "1:", "2:", "3:", "4:"
static const char szDriveNbr[] = "0:";
// Mount the disk
DFATFS::fsmount(disk, szDriveNbr, 1);
xil_printf("Disk mounted\r\n");
fr = file.fsopen("output.txt", FA_WRITE | FA_OPEN_ALWAYS);
if (fr == FR_OK) {
file.fslseek(0);
file.fswrite(printline, 12, &bytesWritten);
fr = file.fsclose();
} else {
xil_printf("Failed to open file to write to\r\n");
}
}
I expect the code to move the file pointer to the end of the file and print a new line after the previous one. When stepping through the program (multiple times through the print subroutine) but it always overwrites.

Related

Storing the last value of a file from SD card using arduino

I am making a device that moves back and fourth and needs to store its last position so that upon power up, the last stored value can be grabbed from the last line of the file on an SD card, and it can resume operation. This file will then be destroyed and re-written. For this particular application homing and other methods can not be used because it must start in the spot it last was. Due to position tracking via encoder, there is no positional memory otherwise.The file is setup to be a single data column seperated by commas.
Currently I am successfully writing to the SD card as position changes, and reading the entire file to be printed on the Serial monitor. However, I really only need the last value. The length of the file will always be different do to system operation.
I have read a lot of different solutions but none of them seem to work for my application.
I can read the entire file using:
void read_file() {
// open the file for reading:
myFile = SD.open("test8.txt");
if (myFile) {
Serial.println("test8.txt:");
// read from the file until there's nothing else in it:
// read from the file until there's nothing else in it:
while (myFile.available()) {
String a = "";
for (int i = 0; i < 9; ++i)
{
int j;
char temp = myFile.read();
if (temp != ',' && temp != '\r')
{ //a=temp;
a += temp;
}
else if (temp == ',' || temp == '\r') {
j = a.toInt();
// Serial.println(a);
Serial.println(j);
break;
}
}
}
// close the file:
myFile.close();
} else {
// if the file didn't open, print an error:
Serial.println("error opening test8.txt");
}
}
This gives me a stream of the values separated by 0 like this:
20050
0
20071
0
20092
0
20113
0
20133
0
Ideally I just need 20133 to be grabbed and stored as an int.
I have also tried:
void read_file_3() {
// open the file for reading:
myFile = SD.open("test8.txt");
if (myFile) {
Serial.println("test8.txt:");
// read from the file until there's nothing else in it:
Serial.println(myFile.seek(myFile.size()));
// close the file:
myFile.close();
} else {
// if the file didn't open, print an error:
Serial.println("error opening test.txt");
}
}
This only returns "1", which does not make any sense to me.
Update:
I have found a sketch that does what I want, however it is very slow due to the use of string class. Per post #6 here: https://forum.arduino.cc/index.php?topic=379209.0
This does grab the last stored value, however it takes quite awhile as the file gets bigger, and may blow up memory.
How could this be done without the string class?
void read_file() {
// open the file for reading:
myFile = SD.open("test8.txt");
if (myFile) {
while (myFile.available())
{
String line_str = myFile.readStringUntil(','); // string lavue reading from the stream - from , to , (coma to comma)
int line = line_str.toInt();
if (line != 0) // checking for the last NON-Zero value
{
line2 = line; // this really does the trick
}
// Serial.print(line2);
// delay(100);
}
Serial.print("Last line = ");
Serial.print(line2);
// close the file:
myFile.close();
// SD.remove("test3.txt");
} else {
// if the file didn't open, print an error:
Serial.println("error opening test.txt");
}
}
Any help would be greatly appreciated!
seek returns true if it succesffuly goes to that position and false if it does not find anything there, like for instance if the file isn't that big. It does not give you the value at that position. That's why you see a 1, seek is returning true that it was able to go to the position (myFile.size()) and that's what you're printing.
Beyond that, you don't want to go to the end of the file, that would be after your number. You want to go to a position 5 characters before the end of the file if your number is 5 digits long.
Either way, once you seek that position, then you still need to use read just like you did in your first code to actually read the number. seek doesn't do that, it just takes you to that position in the file.
EDIT: Since you edited the post, I'll edit the answer to go along. You're going backwards. You had it right the first time. Use the same read method you started with, just seek the end of the file before you start reading so you don't have to read all the way through. You almost had it. The only thing you did wrong the first time was printing what you got back from seek instead of seeking the right position and then reading the file.
That thing you looked up with the String class is going backward from where you were. Forget you ever saw that. It's doing the same thing you were already doing in the first place only it's also wasting a lot of memory and code space in the process.
Use your original code and just add a seek to skip to the end of the file.
This assumes that it's always a 5 digit number. If not then you may need a little bit of tweaking:
void read_file() {
// open the file for reading:
myFile = SD.open("test8.txt");
if (myFile) {
Serial.println("test8.txt:");
/// ADDED THIS ONE LINE TO SKIP MOST OF THE FILE************
myFile.seek(myFile.size() - 5);
// read from the file until there's nothing else in it:
// read from the file until there's nothing else in it:
while (myFile.available()) {
String a = "";
for (int i = 0; i < 9; ++i)
{
int j;
char temp = myFile.read();
if (temp != ',' && temp != '\r')
{ //a=temp;
a += temp;
}
else if (temp == ',' || temp == '\r') {
j = a.toInt();
// Serial.println(a);
Serial.println(j);
break;
}
}
}
// close the file:
myFile.close();
} else {
// if the file didn't open, print an error:
Serial.println("error opening test8.txt");
}
}
See, all I've done is take your original function and add a line to seek the end to it.

How can I write float data from a .txt file to a 2-dimensional array w/ VS2017?

How can I read float data from a .txt file:
8.9 789.3 845.6
2.45 2.25 2.05
. . .and write each float into an array element. I've looked online and I can't find a clear answer or tutorial on how to do this. I'm using VS2017 Enterprise, and I already have the .txt file in my Project's Resource file.
here is a simple example you can use
#include<stdio.h>
#include<stdlib.h>
int main(){
FILE *f=fopen("file.txt","r");
float a;
char b[255];
while(!feof(f)){
fscanf(f,"%s",b);
a=atof(b);
printf("%f\n",a);
} fclose(f);
}
I have always gained more from an explanation of how one reached an answer over just code so here is how I would think through this problem (assuming little knowledge of the chosen language):
First, I need to read through a file. I now go online and search for how to read a file. I find several examples of reading files and pick what makes most sense for me (whether that's streaming the file or reading the whole file into a char *). Once I have figured that out, I can move on to figuring out the 2d array.
To build the 2d array, I first need to initialise a 2d array to the correct size. If one is a true beginner, that might mean looking up how to do initialise a 2d array. Then I can move on to filling the array.
Now, I iterate over the 2d array. If one is a true beginner, that might mean looking up how to iterate over a 2d array. For every cell in the 2d array, I need to parse out the next float from the file and insert it into the cell.
This part, depending on how you've chosen to read the file, can be done in many ways. Assuming that you are streaming the file, you would need to read the next "word" and then transform that text into a float. To do that I would probably search things like 'read text until space or newline in C' and 'convert string to float in C'.
Then all that's left to do is to test it!
Hope that helps.
Use system.IO to read text in the file and then use C# split to convert to an array.
Namespaces
using System;
using System.IO;
using System.Text;
In your code
string path = #"c:\temp\MyTest.txt";
// Open the file to read from.
string readText = File.ReadAllText(path);
string[] strarray = readText.Split(Convert.ToChar(' '));
If you want to convert it to double array. Use linq
double[] darray = readText.Split(Convert.ToChar(' ')).Select(n => Convert.ToDouble(n)).ToArray();
float data from a .txt file to a 2-dimensional array
can't find a clear answer or tutorial on how to do this.
Pseudo code outline
Make these functions
// return 1: success
// return 0: failure
// return -1: EOF or end of line
int read_one_float(FILE *stream, float *f)
fgetc(): read leading white space, if \n encountered, return -1
ungetc(): put non white space character back in stream
if f == NULL, form a dummy location to save data
scanf("%f", f) and return its value
// return > 0: return count of float
// return 0: failure
// return -1: EOF
int read_one_line(FILE *stream, float *f)
count = 0
repeatedly
call read_one_float(f)
if (response != 1) return count
if (f not NULL) f++
count++;
return count
// return > 0: return count of lines
// return 0: failure
// return -1: EOF
int read_FILE(FILE *stream, float **f, int *width)
line = 0;
*width = 0
repeatedly
call read_one_line(f)
if (response <= 0) return line
*width = max (*width, response)
if (f not NULL) f++
line++;
return line
Put together
int main()
open file
width = 0
line count = read_FILE(file, NULL, &width);
allocate f float[count][width]
REWIND file
read_FILE(file, f, &width);
close file
do something with f
deallocate

Trying to read the whole text file

I'm trying to read the whole contain of the txt file, not line by line, but the whole contain
and print it on screen inside a textfield in xcode
i'm using a mix of obj-c and c++ lang:
while(fgets(buff, sizeof(buff), in)!=NULL){
cout << buff; // this print the whole output in the console
NSString * string = [ NSString stringWithUTF8String:buff ] ;
[Data setStringValue:string]; // but this line only print last line inside the textfield instead of printing it all
}
I'm trying to print the whole contain of the file like:
something...
something...
etc...
but instead it just printing the last line to the textfield, please help me
Is there a reason you aren't using Obj-C to read the file? It would be as simple as:
NSData *d = [NSData dataWithContentsOfFile:filename];
NSString *s = [[[NSString alloc] initWithData:d encoding:NSUTF8StringEncoding] autorelease];
[Data setStringValue:s];
Edit: To use the code you have now I would try something like this:
while(fgets(buff, sizeof(buff), in)!=NULL){
NSMutableString *s = [[Data stringValue] mutableCopy];
[s appendString:[NSString stringWithUTF8String:buff]];
[Data setStringValue:s];
}
Read a file, return the content as a C++ string:
// open the file
std::ifstream is;
is.open(fn.c_str(), std::ios::binary);
// put the content in a C++ string
std::string str((std::istreambuf_iterator<char>(is)),
std::istreambuf_iterator<char>());
In your code you are using the C api (FILE* from cstdio). In C, the code is more complex:
char * buffer = 0; // to be filled with the entire content of the file
long length;
FILE * f = fopen (filename, "rb");
if (f) // if the file was correctly opened
{
fseek (f, 0, SEEK_END); // seek to the end
length = ftell (f); // get the length of the file
fseek (f, 0, SEEK_SET); // seek back to the beginning
buffer = malloc (length); // allocate a buffer of the correct size
if (buffer) // if allocation succeed
{
fread (buffer, 1, length, f); // read 'length' octets
}
fclose (f); // close the file
}
To answer the question of why your solution didn't work:
[Data setStringValue:string]; // but this line only print last line inside the textfield instead of printing it all
Assuming that Data refers to a text field, setStringValue: replaces the entire contents of the field with the string you passed in. Your loop reads and sets one line at a time, so at any given time, string is one line from the file.
Views only get told to display when you're not doing anything else on the main thread, so your loop—assuming that you didn't run it on another thread or queue—does not print one line at a time. You read each line and replace the text field's contents with that line, so when your loop finishes, the field is left with the last thing you set its stringValue to—the last line from the file.
Slurping the entire file at once will work, but a couple of problems remain:
Text fields aren't meant for displaying multiple lines. No matter how you read the file, you're still putting its contents in a place that isn't designed for such contents.
If the file is large enough, reading it will take a significant amount of time. If you do this on the main thread, then, during that time, the app will be hung.
A proper solution would be:
Use a text view, not a text field. Text views are built to work with text of any number of lines, and when you create one in a nib, it comes wrapped in a scroll view for free.
Read the file one line or other limited-size chunk at a time, but not in a for or while loop. Use NSFileHandle or dispatch_source, either of which will call a block you provide whenever they read another chunk of the file.
Append each chunk to the text view's storage instead of replacing the entire text with it.
Show a progress indicator when you start reading, then hide it when you finish reading. For extra credit, make it a determinate progress bar, showing the user how far you've gotten through the file.

C++ Reading file using while loop, start at line "x"

I've been stuck on this issue for a while. What I have here is a loop that will read a text file containing file names. The loop reads these lines one by one, and sets it into memory via the variable sFileName. sFileName is later called upon to load an image, and the program does this one by one as the loop loads it. The user then selects a tag for the image and loads the next one. The tag and the image file name are exported into another text file, named imgresults.txt. Now, the text file with the file names is a few thousand lines. So, in the case that the user has to exit the program and tries to continue later, the loop restarts, instead of leaving off at the point when the program was closed.
I am trying to find a way to have the loop start at that point. So far, I decided to use getline() to count how many lines are currently in imgresults.txt, as that will give the number of images that have already been run through the program. This number is stored in the variable "x". I've been doing a lot of research, but I just cannot find how to set a condition for the while loop to begin at line "x". Do you guys have any suggestions? Also, if you need any clarifications, please ask. I only included the code regarding the loop, as the code for loading the image and such is perfect fine.
int _tmain(int argc, _TCHAR* argv[])
{
int value = 0;
int nCounter = 0;
FILE* fIn = NULL;
char * sLine = new char[MAX_FILENAME_SIZE];
char * sFileName = new char [MAX_FILENAME_SIZE];
char * s = new char [MAX_FILENAME_SIZE];
#define ImgListFileName "path"
#define ImgRepository "path"
if ((fIn = fopen(ImgListFileName,"rt"))==NULL)
{
printf("Failed to open file: %s\n",ImgListFileName);
return nCounter;
}
ifstream imgresults;
imgresults.open ("imgresults.txt");
int x=0;
string line;
while(!imgresults.eof()) {
getline (imgresults, line);
x++;
}
srand (time(NULL));
cout << x;
while(!feof(fIn)){
memset(sLine,0,MAX_FILENAME_SIZE*sizeof(char));
memset(sFileName,0,MAX_FILENAME_SIZE*sizeof(char));
memset(s,0,MAX_FILENAME_SIZE*sizeof(char));
fgets(sLine,MAX_FILENAME_SIZE,fIn);
strncpy(s,sLine,65);
strcat(sLine,"\0");
strcat(sFileName,s);
printf (sFileName);
nCounter++;
}
Thanks in advance!
If you really want to use imgresults.txt as the information on where you should start from the input file, then the best you can do is to have a while loop to read x lines from the input file just before the while loop where you read the input file.
while (x--) {
fgets(sLine, MAX_FILENAME_SIZE, fIn);
}
Better solution would probably be to write state of processing to another file so that you would not have to read input file line by line, but you could immediately seek to a known offset in the file.
Use ifstream::tellg to retrieve and store the current position of the file when the programm was closed.
Use ifstream::seekg to restore that position when the porgramm restarts.
Before you read each line, save the current offsets in your input and output file to a separate file, seeking back to the beginning and overwriting the existing data each time.
When/if you restart, read the offsets from that file, seek to those points, and start working from there.
You can just read lines in parallel from both files and stop when you reach the end of results file. When the loop ends, you have already discarded the file names that were already processed.
ifstream results("results.txt");
ifstream names("names.txt");
if (results && names) {
std::string temp1, temp2;
while (getline(results, temp1) && getline(names, temp2)) ; /* do nothing */
}
if (names) {
// process the rest
}
Not the most efficient solution, but it saves you the hassle of saving offsets. Just make sure that before the very first processing the results file is completely empty (or doesn't exist at all), otherwise this code will skip the first line of names file.

Reading file with visual c++ form behaves differently than reading in C program

I'm build a graphical program using visual c++ form. I'm trying to read a file to a string. The contents of the file is simple html code.
Now, if i create a blank project and create a .c file with this code:
FILE *f;
int tamanho;
char *asd;
f=fopen("mail.txt","r");
if(f==NULL)
erro("Erro abrir file");
fseek(f,0,SEEK_END);
tamanho=ftell(f);
rewind(f);
asd=(char *)malloc(tamanho+1);
fread(asd,1,tamanho,f);
It copies the whole to the string.
However if I create a windows form application and write the same code it only copies a few lines of my file.
fread() does not guarantee to read everything you ask for.
You need to check the return value to see how much was actually read.
You may need to do this in a loop until you have read everything you want.
size_t read = 0;
while(read != tamanho)
{
size_t amount = fread(asd + read,1,tamanho - read,f);
if (amount == 0)
{ // You may want to check for read errors here
}
read += amount;
}
Missing a while loop? That way u make sure u reach end of file properly