Coffeehouse Thread

20 posts

Forum Read Only

This forum has been made read only by the site admins. No new threads or comments can be added.

Reading int from file in C#

Back to Forum: Coffeehouse
  • User profile image
    algorith

     I'm kind of new to C# (come from a C++ background), and I've got a question regarding file reading. Is there a way to read a large number of ints or doubles from a file directly (as easy as in C++)?

    I've looked into StreamReader, StringReader and BinaryReader and while I can get it done, I think I must be missing something since it's not nearly as straightforward as it is in C++. So far I've used StreamReader to read the entire file, then use ' ' as a delimiter and get my ints that way. 

    Basically I'm looking to do the C# equivalent of this:

    std::ifstream ins;
    ins.open(file_name.c_str());
    if(ins.is_open())
    {
         while(ins)
         {
              ins >> tmp;
              arr[iter] = tmp; iter++;
          }
    }
    
    

  • User profile image
    kettch

    @algorith: Is it just a text file or a binary file of some kind?

    If it's text, then the following should suffice:

    List<string> items = System.IO.File.ReadAllLines(@"C:\temp\somefile.txt");

  • User profile image
    cbae

    Is this a text file or a binary file? And what's the delimiter again? A space?

  • User profile image
    cbae

    @kettchSmiley

  • User profile image
    magicalclick

    humm... I actually don't know. I normally use line return instead of space, so, I simply do readline().

    You can:

    1) read() and decide if you want to include as part of the integer or not.

    2) readblock() a length and split the string using the space character.

    Both are not as efficient as your example though.

    If you have the the authority to change the file format, using line return would make your problem a lot easier. Or actually it is best to use binary file as it will save tons of data size and makes reading the HDD much more effective.

    Probably will need to wait for other suggestions from others.

    Leaving WM on 5/2018 if no apps, no dedicated billboards where I drive, no Store name.
    Last modified
  • User profile image
    algorith

     @kettch, your method is basically how I've been doing it but it requires more code to separate the string into the numbers I want and put them into the correct spot in the 2D array. 

    @cbae, in my case space is the delimiter. A delimiter is just some separator of data. 

    It's a txt file, an example would be like so:

    2 11 3 10
    1 9 4 6
    6 13 7 8
    5 14 15 12
     
    So what I want is to read int by int and put each number into my 2-dimensional array. I guess it boils 
    down to if I can do something like this in C#:

    inFile >> someInt;  // for ints seperate by space

     

  • User profile image
    algorith

    @magicalclick, I've tried Read() and it gets a single char, the problem with this and the ReadBlock() approach is that I actually don't know the length of each number and they could differ in length. I could certainly just read the entire line and the break it up using space but that wouldn't be as elegant as the C++ solution. 

  • User profile image
    Sven Groot

    No, there is no such thing. The closest you can get is this:

    foreach( string line = File.ReadLines(fileName) )
    {
        foreach( string value in line.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
        {
            someInt = Convert.ToInt32(value);
        }
    }

    Which could be very memory-intensive if the file contains very long lines.

    There may be third party libraries that are better at this, but I wouldn't know any off-hand.

  • User profile image
    algorith

     Oh well, thanks for clearing it up Sven. 

  • User profile image
    androidi

    Could there be a method which takes a stream of characters & optional function which can eg. replace newline or string with space & a delimiter (like space) and when executed it immediately starts yielding new streams (without waiting for the first delimiter to occur) that can be read up to the delimiter (or current position [up to that delimiter specific to the yield] when del. not yet encountered) and if none is encountered, it would just yield the whole original stream (wrapped) with some flag indicating that no delimiters were found?

    I guess if you want performance and simplicity in C# expect to write a bunch of code. And still it won't perform like C++. This whole "C++ reneissance" is a bunch of non-sense, for now. I'm still out for a language that's written and reads more like C# but if I want I can paste in some C++ code and link native libs etc without perf penalty. Is that too much to ask?

  • User profile image
    Sven Groot

    By the way, one of the neat things of the STL is that you can actually write the OP's code like this:

    std::ifstream input(fileName.c_str());
    std::vector<int> values;
    if( input )
        std::copy(std::istream_iterator<int>(input), std::istream_iterator<int>(), std::back_inserter(values));
    

    The C# equivalent of that would be to use LINQ, I guess:

    var values = from line in File.ReadLines(fileName)
                 from value in line.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)
                 select Convert.ToInt32(value);
    

  • User profile image
    Sven Groot

    Alright, because I was bored, here's a class that extracts strings from a file on whitespace boundaries, in a similar way that C++ iostreams do.

    class WordReader : IDisposable
    {
        private StreamReader _reader;
        private char[] _buffer = new char[1024];
        private int _bufferPos;
        private int _bufferSize;
    
        public WordReader(string file)
        {
            _reader = File.OpenText(file);
        }
    
        public string ReadWord()
        {
            // Possible optimization: reuse the StringBuilder
            StringBuilder result = new StringBuilder(80);
            // Skip whitespace
            while( (_bufferPos < _bufferSize || FillBuffer()) && char.IsWhiteSpace(_buffer[_bufferPos]) )
            {
                ++_bufferPos;
            }
    
            // Read word
            while( (_bufferPos < _bufferSize || FillBuffer()) && !char.IsWhiteSpace(_buffer[_bufferPos]) )
            {
                result.Append(_buffer[_bufferPos]);
                ++_bufferPos;
            }
    
            if( result.Length == 0 )
                return null;
            else
                return result.ToString();
        }
    
        public IEnumerable<string> ReadWords()
        {
            string value;
            while( (value = ReadWord()) != null )
                yield return value;
        }
    
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
    
        protected virtual void Dispose(bool disposing)
        {
            if( disposing )
                _reader.Dispose();
        }
    
        private bool FillBuffer()
        {
            _bufferSize = _reader.Read(_buffer, 0, _buffer.Length);
            _bufferPos = 0;
            return _bufferSize > 0;
        }
    }
    

    Which can then be used like this:

    int[] values;
    using( WordReader reader = new WordReader(fileName) )
    {
        values = reader.ReadWords().Select(word => Convert.ToInt32(word)).ToArray();
    }
    

    Big Smile

  • User profile image
    David7738

    ,algorith wrote

     

    2 11 3 10
    1 9 4 6
    6 13 7 8
    5 14 15 12
     
    So what I want is to read int by int and put each number into my 2-dimensional array. I guess it boils 
    down to if I can do something like this in C#:

     

    They are not int's to begin with they are char's or strings the character 2 will come in as int 32 space as int 20 as the file is not a binary file but a 'text' file. so up to the newline we have

    32 20 31 31 20 33 20 31 30 0d 0a

     

     

  • User profile image
    Sven Groot

    @David7738: The C++ code he posted converts the numbers in the text to integers. The ASCII values of the characters are not relevant.

  • User profile image
    figuerres

    ,David7738 wrote

    *snip*

    They are not int's to begin with they are char's or strings the character 2 will come in as int 32 space as int 20 as the file is not a binary file but a 'text' file. so up to the newline we have

    32 20 31 31 20 33 20 31 30 0d 0a

     

     

    i have seen a few posts here and in the techoff area where the OP's use terms in a very confusing way....   they seem to not really know the difference between a text file and a binary file.

    and nowdays with UNICODE it's possibly worse than the old days of simple ascii text files!

    reading a char may or may not be the same as reading a byte if the file is saved as unicode.

  • User profile image
    evildictait​or

    reading a char may or may not be the same as reading a byte if the file is saved as unicode.

    I (and C/C++) usually define char as a unsigned __int8 so a char is a byte (unless you're really crazy and have 9 bit bytes or something). A unicode character is not a char.

  • User profile image
    blowdart

    ,figuerres wrote

    reading a char may or may not be the same as reading a byte if the file is saved as unicode.

    Well that's why you read the first two or three bytes and look for a byte order mark

  • User profile image
    figuerres

    ,evildictait​or wrote

    *snip*

    I (and C/C++) usually define char as a unsigned __int8 so a char is a byte (unless you're really crazy and have 9 bit bytes or something). A unicode character is not a char.

    but .net char is 16bits / 2 bytes.

    so what char means is not the same in .net as in classic C and C++

Conversation locked

This conversation has been locked by the site admins. No new comments can be made.