0

I'm reading a text file saved on my ESP8266 device (using LittleFS).

while (myFile.available()) {
        Serial.write(myFile.read());
    }

My goal is to save file content ( each line ) to a String / char array. myFile.read() returns a binary - and I'm looking for a quick and elegant way to do so ( as in Serial.write which converts it to text ).

Guy

4
  • It is unclear, what you are trying to do. Binary and characters are just different representations of the same data. Serial.write() just sends the data out as it is and the Serial monitor then interprets that data as ASCII. But the Arduino does not care about, what the data represents. For the Arduino, everything is just binary data. The character interpretation is only for us humans and is done in the Serial monitor, not on the Arduino. So, when you want to put the data into a char array, just do so array[position] = myFile.read(). – chrisl Jul 30 '20 at 8:59
  • @chrisl - I'm trying to exrract the text. When I did as you explained... I only got a bunch of numbers – Guy . D Jul 30 '20 at 9:01
  • You need to provide the full code, where you only got a bunch of numbers. Its all about, how you are writing or printing it to Serial. A character can also be interpreted as a number, so likely you are just outputting it to Serial the wrong way. – chrisl Jul 30 '20 at 9:05
  • the point is, specially write does no conversion. print converts a number to text representation, by decomposing it to digits and mapping every digit to ascii.. so from a byte with value 123 it prints string "123" consisting of characters '1', '2', '3'. but write sends 123 as t is and Serial Monitor prints the character with this value, which is '{'. – Juraj Jul 30 '20 at 9:40
2

myFile.read() returns one character. That character can be represented as a number (such as 65 for 'A') or a character, or whatever you want. Everything is just a number.

Letters are just our personal representation of certain numbers as humans. You could think of it as the numbers represented in base 256, where each value between 0 and 255 is assigned a unique symbol.

Serial.write() just passes that number verbatim to the computer which then maps it in the serial monitor to the corresponding letter in the ASCII table.

Thanks to the object-oriented and polymorphic nature of the Arduino API (see C++ Polymorphism) there is no difference between reading from a file and reading from serial. They all inherit the same Stream class that gives you the same functions regardless of what you're reading.

So you could, like Serial, read each byte from the file one at a time until you reach the line ending character(s) (\n for a Unix file, or \r\n for a Windows file) and append each to the end of a string (either a String object, which is frowned upon, though less so on more capable MCUs like the ESP8266 and ESP32, or a char array).

Alternatively you could use one of the helper functions of the Stream class, such as readStringUntil(), which reads an entire string up to (and discarding) the specified terminating character and returns a String.

However both those have problems when it comes to building up an array of all the results, especially if you don't know beforehand how many lines there are in the file - since in C++ arrays have a fixed size.

A better solution, if you really do want it all in RAM (see below), might be instead to, at first, forget the idea of lines and just read the entire file into memory. Once it is in memory you can read through the entire block of data counting the number of \n bytes (and add one if it doesn't end with \n). That will give you the number of lines in the file.

You can then allocate an array of pointers with the same number of entries as there are lines.

From there you can use strtok() on the data to split it into chunks on the \n bytes and assign each chunk to one of the pointers in your array. That array then becomes a kind of index to the data.

But one has to ask... why do you want to store this data in RAM anyway? You have it in flash, and that is quite fast to access (not as fast as internal flash in a traditional MCU, but still many times faster than an SD card for example). If ease of navigating the data is your goal, maybe you should be thinking of better ways of storing your data. Depending on what that data is maybe a fixed size record based file structure using a struct to manipulate the data would be a better solution - then you can just seek to multiples of the record (or struct) size to almost instantly get to different entries in the file.

If it's textual data then maybe reading through the file and recording the file offsets of the start of each line in an array (note: two passes - one to count the lines for allocating the array and one for recording the offsets into the array) similar to the indexing of the data block described above would be a better solution. That way you're only storing 4 bytes per entry in your array rather than all the data. Seeking is instant (just seek to the offset stored in the array for the line you want) and you're not having to store all the data in RAM.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.