Прочитать текстовый файл с определенной позиции до определенной длины - PullRequest
1 голос
/ 22 декабря 2011

Из-за того, что я получил очень плохой файл данных, мне пришлось придумать код для чтения из текстового файла без разделителей из определенной начальной позиции и определенной длины для создания работоспособного набора данных. Текстовый файл не разделен любым способом, , но У меня есть начальная и конечная позиции каждой строки, которую мне нужно прочитать. Я пришел с этим кодом, но я получаю сообщение об ошибке и не могу понять, почему, потому что, если я заменю 395 на 0, это работает ..

например. Начальная позиция номера счета = 395, конечная позиция = 414, длина = 20

using (StreamReader sr = new StreamReader(@"\\t.txt"))
{                    
    char[] c = null;                   
    while (sr.Peek() >= 0)
    {
        c = new char[20];//Invoice number string
        sr.Read(c, 395, c.Length); //THIS IS GIVING ME AN ERROR                      
        Debug.WriteLine(""+c[0] + c[1] + c[2] + c[3] + c[4]..c[20]);
    }
}

Вот ошибка, которую я получаю:

System.ArgumentException: Offset and length were out of bounds for the array 
                          or count is greater than the number of elements from
                          index to the end of the source collection. at
                          System.IO.StreamReader.Read(Char[] b

Ответы [ 6 ]

4 голосов
/ 22 декабря 2011

Обратите внимание:

Seek() слишком низкий уровень для того, что хочет OP.См. этот ответ вместо этого для построчного анализа.

Также, как упоминал Джордан, Seek() имеет проблему кодировки символов и переменных размеров символов (например, для не-ASCII ине-ANSI файлы, такие как UTF, что, вероятно, не относится к этому вопросу).Спасибо за указание на это.


Оригинальный ответ

Seek() доступен только в потоке, поэтому попробуйте использовать sr.BaseStream.Seek(..) или использовать другой поток, такой как:

using (Stream s = new FileStream(path, FileMode.Open))
{
    s.Seek(offset, SeekOrigin.Begin);
    s.Read(buffer, 0, length);
}
1 голос
/ 23 декабря 2011

(новый ответ на основе комментариев)

Вы анализируете данные счета-фактуры с каждой записью в новой строке, и требуемые данные имеют фиксированное смещение для каждой строки. Stream.Seek () слишком низкий уровень для того, что вы хотите сделать, потому что вам потребуется несколько запросов, по одному на каждую строку. Скорее используйте следующее:

int offset = 395;
int length = 20;
using (StreamReader sr = new StreamReader(@"\\t.txt"))
{
    while (!sr.EndOfStream)
    {
        string line = sr.ReadLine();
        string myData = line.Substring(offset, length);
    }
}
0 голосов
/ 27 февраля 2016

Решил это давным-давно, просто хотел опубликовать решение, которое было предложено

 using (StreamReader sr = new StreamReader(path2))
        {
          string line;
            while ((line = sr.ReadLine()) != null)
            {             
                dsnonhb.Tables[0].Columns.Add("InvoiceNum"  );
                dsnonhb.Tables[0].Columns.Add("Odo"         );
                dsnonhb.Tables[0].Columns.Add("PumpVal"      );
                dsnonhb.Tables[0].Columns.Add("Quantity"    );


                DataRow myrow;
                myrow = dsnonhb.Tables[0].NewRow();
                myrow["No"] = rowcounter.ToString();
                myrow["InvoiceNum"] = line.Substring(741, 6);
                myrow["Odo"] = line.Substring(499, 6);
                myrow["PumpVal"] = line.Substring(609, 7);
                myrow["Quantity"] = line.Substring(660, 6);
0 голосов
/ 26 февраля 2016

Я создал класс с именем AdvancedStreamReader в моем Helpers проекте на git hub здесь:

https://github.com/jsmunroe/Helpers/blob/master/Helpers/IO/AdvancedStreamReader.cs

Это довольно надежно. Это подкласс StreamReader и сохраняет все эти функции без изменений. Есть несколько предостережений: а) он сбрасывает положение потока при его создании; б) вы не должны искать BaseStream во время использования ридера; в) вам нужно указать тип символа новой строки, если он отличается от окружения и файл может использовать только один тип. Вот несколько юнит-тестов, чтобы продемонстрировать, как это используется.

    [TestMethod]
    public void ReadLineWithNewLineOnly()
    {
        // Setup
        var text = $"ƒun ‼Æ¢ with åò☺ encoding!\nƒun ‼Æ¢ with åò☺ encoding!\nƒun ‼Æ¢ with åò☺ encoding!\nHa!";
        var bytes = Encoding.UTF8.GetBytes(text);
        var stream = new MemoryStream(bytes);
        var reader = new AdvancedStreamReader(stream, NewLineType.Nl);
        reader.ReadLine();

        // Execute
        var result = reader.ReadLine();

        // Assert
        Assert.AreEqual("ƒun ‼Æ¢ with åò☺ encoding!", result);
        Assert.AreEqual(54, reader.CharacterPosition);
    }


    [TestMethod]
    public void SeekCharacterWithUtf8()
    {
        // Setup
        var text = $"ƒun ‼Æ¢ with åò☺ encoding!{NL}ƒun ‼Æ¢ with åò☺ encoding!{NL}ƒun ‼Æ¢ with åò☺ encoding!{NL}Ha!";
        var bytes = Encoding.UTF8.GetBytes(text);
        var stream = new MemoryStream(bytes);
        var reader = new AdvancedStreamReader(stream);

        // Pre-condition assert
        Assert.IsTrue(bytes.Length > text.Length); // More bytes than characters in sample text.

        // Execute
        reader.SeekCharacter(84);

        // Assert
        Assert.AreEqual(84, reader.CharacterPosition);
        Assert.AreEqual($"Ha!", reader.ReadToEnd());
    }

Я написал это для себя, но надеюсь, что это поможет другим людям.

0 голосов
/ 22 декабря 2011

Вот мое предложение для вас:

using (StreamReader sr = new StreamReader(@"\\t.txt"))
{
    char[] c = new char[20];  // Invoice number string 
    sr.BaseStream.Position = 395;
    sr.Read(c, 0, c.Length); 
}
0 голосов
/ 22 декабря 2011

395 - это индекс в массиве c, с которого вы начинаете писать.Там нет индекса 395, максимум - 19. Я бы предложил что-то вроде этого.

StreamReader r;
...
string allFile = r.ReadToEnd();
int offset = 395;
int length = 20;

А затем используйте

allFile.Substring(offset, length)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...