Is readline fixed ReadLineEx

Years ago I stared using ReadLineEx because it was necessary. Now I can’t get it working, do I even need it? This is what I was using.


public static string ReadLine(string file, int line)
        {
            if (Detect.SD_Card() & File.Exists(file))
            {
                lock (CardLock)
                {
                    using (StreamReader r = new StreamReader(file))
                    {
                        SAL.StatusLED[3].Write(true);

                        int i = 0;

                        while (ReadLineEx(r) != null & i != line) 
                        { 
                            i++; 
                        }

                        SAL.StatusLED[3].Write(false);

                        if (i == line)
                        {
                            return ReadLineEx(r);
                        }
                    }
                }
            }
            return "EOF";
        }


public static string ReadLineEx(StreamReader sr)
        {
            int newChar = 0;
            int bufLen = 512; // NOTE: the smaller buffer size.
            char[] readLineBuff = new char[bufLen];
            int growSize = 512;
            int curPos = 0;
            while ((newChar = sr.Read()) != -1)
            {
                if (curPos == bufLen)
                {
                    if ((bufLen + growSize) > 0xffff)
                    {
                        throw new Exception();
                    }
                    char[] tempBuf = new char[bufLen + growSize];
                    Array.Copy(readLineBuff, 0, tempBuf, 0, bufLen);
                    readLineBuff = tempBuf;
                    bufLen += growSize;
                }
                readLineBuff[curPos] = (char)newChar;
                if (readLineBuff[curPos] == '\n')
                {
                    return new string(readLineBuff, 0, curPos);
                }
                if (readLineBuff[curPos] == '\r')
                {
                    sr.Read();
                    return new string(readLineBuff, 0, curPos);
                }
                curPos++;
            }

            if (curPos == 0) return null; // Null fix.
            return new string(readLineBuff, 0, curPos);
        }

If I don’t need it, can I have an example of using readline properly.

I’m successfully using the code above to loop through the lines in a txt file on an SD_Card. Except when I read about the 10th line. It fails with the following error.


GC: 10msec 1011444 bytes used, 6328224 bytes available
Type 0F (STRING              ):   2808 bytes
Type 11 (CLASS               ):  11484 bytes
Type 12 (VALUETYPE           ):   4932 bytes
Type 13 (SZARRAY             ):   8508 bytes
  Type 01 (BOOLEAN             ):     84 bytes
  Type 03 (U1                  ):    876 bytes
  Type 04 (CHAR                ):    516 bytes
  Type 07 (I4                  ):    720 bytes
  Type 0F (STRING              ):   1944 bytes
  Type 11 (CLASS               ):   3540 bytes
  Type 12 (VALUETYPE           ):    828 bytes
Type 15 (FREEBLOCK           ): 6328224 bytes
Type 16 (CACHEDBLOCK         ):    240 bytes
Type 17 (ASSEMBLY            ):  35448 bytes
Type 18 (WEAKCLASS           ):     48 bytes
Type 19 (REFLECTION          ):    192 bytes
Type 1B (DELEGATE_HEAD       ):    540 bytes
Type 1D (OBJECT_TO_EVENT     ):    216 bytes
Type 1E (BINARY_BLOB_HEAD    ): 935664 bytes
Type 1F (THREAD              ):   1920 bytes
Type 20 (SUBTHREAD           ):    240 bytes
Type 21 (STACK_FRAME         ):   3048 bytes
Type 22 (TIMER_HEAD          ):     72 bytes
Type 23 (LOCK_HEAD           ):    120 bytes
Type 24 (LOCK_OWNER_HEAD     ):     48 bytes
Type 27 (FINALIZER_HEAD      ):    384 bytes
Type 31 (IO_PORT             ):    288 bytes
Type 34 (APPDOMAIN_HEAD      ):     72 bytes
Type 36 (APPDOMAIN_ASSEMBLY  ):   5172 bytes
    #### Exception System.IO.IOException - CLR_E_FILE_IO (5) ####
    #### Message: 
    #### Microsoft.SPOT.IO.NativeFileStream::GetLength [IP: 0000] ####
    #### System.IO.FileStream::get_Length [IP: 001b] ####
    #### Industry_ONE.Tools.FileManagement.FileManager::ReadLineEx [IP: 00ac] ####
    #### Industry_ONE.Tools.FileManagement.FileManager::ReadLine [IP: 003b] ####
    #### Industry_ONE.Tools.FileManagement.Log::ReadLine [IP: 0050] ####
    #### DEMO.Tools.Diag::ReadLog [IP: 009b] ####
    #### DEMO.Tools.Diag::MENU_Actions [IP: 0153] ####
    #### DEMO.Program::menu_return [IP: 006c] ####
    #### DEMO.MENU::RunThisOption [IP: 0005] ####
    #### DEMO.MENU::selectMenu [IP: 0067] ####
    #### DEMO.MENU::doMenuStuff [IP: 0130] ####
    #### DEMO.MENU::on_keyTimerTick [IP: 0004] ####
A first chance exception of type 'System.IO.IOException' occurred in Microsoft.SPOT.IO.dll

that exception happening just after a GC leads me to believe your file stream went out of scope and was GCed, then your next read dies… I’d be checking code outside that section you showed above.

I cut out as much crap as possible and ended up with the below solution. I can read line by line until about line 100. GC runs and kills the line read.


using System;
using Microsoft.SPOT;
using System.IO;
using Microsoft.SPOT.Hardware;
using Microsoft.SPOT.IO;
using System.Threading;

using GHI.IO.Storage;

namespace test
{
    public class Program
    {
        private static Object LogLock = new Object();
        private static Object CardLock = new Object();

        public static string FullLogFile = @ "\SD\Logs\FullLog.txt";
        public static string ErrorLogFile = @ "\SD\Logs\ErrorLog.txt";

        private static string FullLog = "";
        private static string ErrorLog = "";

        public static InputPort CD = new InputPort(GHI.Pins.G120.P2_21, false, Port.ResistorMode.PullUp); //This will depend on your board.

        public static void Main()
        {
            int x = 0;
            while (true)
            {
                Debug.Print(ReadLine(x, 0));
                Debug.Print(x.ToString());
                Thread.Sleep(100);
                x++;
            }
        }

        public static string ReadLine(int line, int Level = 0)
        {
            lock (LogLock)
            {
                string name = FullLogFile;
                string memorylog = FullLog;

                if (Level == 1)
                {
                    name = ErrorLogFile;
                    memorylog = ErrorLog;
                }

                if (Detect_SD_Card())
                {
                    if (File.Exists(name))
                    {
                        try
                        {
                            string s = FileManager_ReadLine(name, line);

                            return s;
                        }
                        catch
                        {
                            return "      End of Log";
                        }
                    }
                    else
                    {
                        return "      End of Log";
                    }
                }
                else
                {
                    try
                    {
                        string[] StringLine = (memorylog.Split('\n'));
                        if (line >= StringLine.Length)
                        {
                            return "      End of Log";
                        }
                        else
                        {
                            return StringLine[line];
                        }
                    }
                    catch
                    {
                    }
                }
                return "      End of Log";
            }
        }

        public static string FileManager_ReadLine(string file, int line)
        {
            if (Detect_SD_Card() & File.Exists(file))
            {
                lock (CardLock)
                {
                    using (StreamReader r = new StreamReader(file))
                    {
                        //SAL.StatusLED[3].Write(true);

                        int i = 0;

                        while (FileManager_ReadLineEx(r) != null & i != line)
                        {
                            i++;
                        }

                        //SAL.StatusLED[3].Write(false);

                        if (i == line)
                        {
                            return FileManager_ReadLineEx(r);
                        }
                    }
                }
            }
            return "EOF";
        }

        public static string FileManager_ReadLineEx(StreamReader sr)
        {
            int newChar = 0;
            int bufLen = 512; // NOTE: the smaller buffer size.
            char[] readLineBuff = new char[bufLen];
            int growSize = 512;
            int curPos = 0;
            while ((newChar = sr.Read()) != -1)
            {
                if (curPos == bufLen)
                {
                    if ((bufLen + growSize) > 0xffff)
                    {
                        throw new Exception();
                    }
                    char[] tempBuf = new char[bufLen + growSize];
                    Array.Copy(readLineBuff, 0, tempBuf, 0, bufLen);
                    readLineBuff = tempBuf;
                    bufLen += growSize;
                }
                readLineBuff[curPos] = (char)newChar;
                if (readLineBuff[curPos] == '\n')
                {
                    return new string(readLineBuff, 0, curPos);
                }
                if (readLineBuff[curPos] == '\r')
                {
                    sr.Read();
                    return new string(readLineBuff, 0, curPos);
                }
                curPos++;
            }

            if (curPos == 0) return null; // Null fix.
            return new string(readLineBuff, 0, curPos);
        }

        public static bool Detect_SD_Card()
        {
            //If mounted, return true; 
            //Else try the CD[Chip detect] port to see if a card is inserted;
            //If failing to initilise input port or CD is empty, return false;
            //If not mounted, but card is seen as inserted, Try mouting;
            //If mounting works then return true. Else,return false;
            //If card won't mount -format
            if (CD.Read())
            {
                Debug.Print("Card not inserted.");

                return false;
            }

            try
            {
                if (VolumeInfo.GetVolumes()[0].IsFormatted)
                {
                    string rootDirectory = VolumeInfo.GetVolumes()[0].RootDirectory;

                    return true;
                }
            }
            catch
            {
                Debug.Print("nothing mounted yet?");
            }

            try
            {
                // Card might be inserted. Lets try mounting.
                SDCard SD = new SDCard();

                // Mount the file system        
                SD.Mount();

                if (VolumeInfo.GetVolumes()[0].IsFormatted)
                {
                    Debug.Print("SD Card Mounted!");

                    return true;
                }
            }
            catch
            {
                Debug.Print("CD pin indicates a card is present, Can't Mount");
            }

            try
            {
                //FileManager.Format();

                //Debug.Print("Card Formatted");

                return true;
            }
            catch
            {
                Debug.Print("Can't format the card");

                return false;
            }
        }
    }
}

Thanks in advance.

I think…

your problem is where you declare the SD card inside Detect_SD_Card(). Promote that to a Program scoped object and try again.

2 Likes

:clap: :clap: :clap: :clap: You legend, That was it. I declared the sd in the program and it fixed the problem.

Thanks a ton.

Now the garbage collector runs but I don’t get the exception.