Прочитал топик получше.
т.к. у тебя только разделитель, то читай сам напрямую.
case StateEnum.FieldStart :
if ( Ch == Delimiter)
aList.Add(string.Empty);
else
{
State = StateEnum.ScanField;
StartPos=Inx;
}
break;
case StateEnum.ScanField :
if ( Ch == Delimiter )
{
int CopyCount=Inx-StartPos;
aList.Add(S.Substring(StartPos,CopyCount));
State = StateEnum.FieldStart;
}
break;
if (State == StateEnum.ScanField)
{
int CopyCount=Inx-StartPos;
aList.Add(S.Substring(StartPos,CopyCount));
}
Так же можешь усложнить себе задачу и самому еще парсить строку из буфера, добавив
состояние на конец строки, с подгрузкой данных в буфер
и солнце б утром не вставало, когда бы не было меня
KS>Да-да. Но за ссылочку спасибо.
Если это твой формат данных, то проще сделать аналог бинарной сериализации.
Если количество колононок одинаково, то записывать сначала длину строки, потом строку.
Если количество колонок не одинаково, то сначала записываем количество колонок потом строки.
Это будет значительно быстрее чем парсинг.
Используй BinaryWriter для записи и BinaryReader для чтения.
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, samius, Вы писали:
KS>>Ой! Время чтения, конечно же, увеличивается. KS>>Есть мысли почему так?
S>Read() — читает по одному символу, т.е. на каждый символ добавляется вызов. Наверное, речь не о нем.
Ессно.
S>Read(char[], Int32, Int32) — тут многое зависит от диапазона, с которым он вызывается. Навскидку не должен быть медленнее чем ReadLine().
Я тоже считаю, что не должен быть медленнее.
Всё, спасибо, разобрался. Буду писать свой ReadLine.
Здравствуйте, Serginio1, Вы писали:
S> Так же можешь усложнить себе задачу и самому еще парсить строку из буфера, добавив S>состояние на конец строки, с подгрузкой данных в буфер
Здравствуйте, Serginio1, Вы писали:
S>Здравствуйте, Kore Sar, Вы писали:
KS>>Здравствуйте, Serginio1, Вы писали:
S>>>Вообщето у тебя не CSV S>>>http://rsdn.ru/forum/dotnet/3303143.aspx
KS>>Да-да. Но за ссылочку спасибо. S> Если это твой формат данных, то проще сделать аналог бинарной сериализации. S>Если количество колононок одинаково, то записывать сначала длину строки, потом строку. S>Если количество колонок не одинаково, то сначала записываем количество колонок потом строки. S> Это будет значительно быстрее чем парсинг.
S>Используй BinaryWriter для записи и BinaryReader для чтения.
Данные приходят с линкус-сервера, который написан на С++.
Всё это проектировали не мы, нам досталось по наследству. Я бы конечно сделал хранилище бинарным, будь на то моя воля.
Здравствуйте, Kore Sar, Вы писали:
KS>Данные приходят с линкус-сервера, который написан на С++. KS>Всё это проектировали не мы, нам досталось по наследству. Я бы конечно сделал хранилище бинарным, будь на то моя воля.
Сочувствую. Если строки не превышают определенный размер Например кэш процессора, то лучше использовать кольцевой буфер,
либо со сдвигом остатка строки в начало при достижении конца строки. Алгоритмы достаточно просты. Со сдвигом немного проще,
и корректировать начало строки
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Serginio1, Вы писали:
S>Здравствуйте, Kore Sar, Вы писали:
KS>>Данные приходят с линкус-сервера, который написан на С++. KS>>Всё это проектировали не мы, нам досталось по наследству. Я бы конечно сделал хранилище бинарным, будь на то моя воля. S> Сочувствую. Если строки не превышают определенный размер Например кэш процессора, то лучше использовать кольцевой буфер, S>либо со сдвигом остатка строки в начало при достижении конца строки. Алгоритмы достаточно просты. Со сдвигом немного проще, S>и корректировать начало строки
И это всё под дотнетом? Или речь уже о unmanaged?
Здравствуйте, Kore Sar, Вы писали:
KS>И это всё под дотнетом? Или речь уже о unmanaged?
Конечно под дотнетом. Разница в скорости минимальна.
Единственно, что скорее всего у тебя данные в кодировке 1251, то искать побайтно, а считывать строку через энкодер.
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Serginio1, Вы писали:
S>Здравствуйте, Kore Sar, Вы писали:
KS>>И это всё под дотнетом? Или речь уже о unmanaged? S> Конечно под дотнетом. Разница в скорости минимальна. S> Единственно, что скорее всего у тебя данные в кодировке 1251, то искать побайтно, а считывать строку через энкодер.
Еще можно использовать BitArray Что бы отсеивать символы ',' и '\r' и '\n'
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Kore Sar, Вы писали:
KS>Данные приходят с линкус-сервера, который написан на С++. KS>Всё это проектировали не мы, нам досталось по наследству. Я бы конечно сделал хранилище бинарным, будь на то моя воля.
Доброе ....
Что вы делаете с этими данными? Если льете в базу — посмотрите в сторону bulk...
Здравствуйте, Аноним, Вы писали:
А>Здравствуйте, Kore Sar, Вы писали:
KS>>Данные приходят с линкус-сервера, который написан на С++. KS>>Всё это проектировали не мы, нам досталось по наследству. Я бы конечно сделал хранилище бинарным, будь на то моя воля.
А>Доброе ....
А>Что вы делаете с этими данными? Если льете в базу — посмотрите в сторону bulk...
Здравствуйте, Serginio1, Вы писали:
S>Здравствуйте, Serginio1, Вы писали:
S>>Здравствуйте, Kore Sar, Вы писали:
KS>>>И это всё под дотнетом? Или речь уже о unmanaged? S>> Конечно под дотнетом. Разница в скорости минимальна. S>> Единственно, что скорее всего у тебя данные в кодировке 1251, то искать побайтно, а считывать строку через энкодер. S> Еще можно использовать BitArray Что бы отсеивать символы ',' и '\r' и '\n'
У меня пробел в знаниях. Что это? — "использовать кольцевой буфер, либо со сдвигом остатка строки в начало при достижении конца строки"
Можно ссылками.
И, да, я уже говорил, что у нас чистый ASCII. Никаких 1251.
Re[7]: Ускорить чтение CSV файла.
От:
Аноним
Дата:
20.07.09 08:11
Оценка:
Здравствуйте, Kore Sar, Вы писали:
А>>Доброе ....
А>>Что вы делаете с этими данными? Если льете в базу — посмотрите в сторону bulk...
KS>Не льём. Мы их считаем. Статистика и всё такое...
Доброе ...
Для объемов данных, которые вы представили — имхо имеет смысл обратить взор в сторону субд...
Oracle (sqlldr) и MsSql (bcp) — имеют средства для массовых вставок ...
Для бесплатных субд можно посмотреть наличие этой опции...
Опять таки функционал по агрегации есть в самой субд ...
Я так понимаю у вас руки не связаны по постобработке предоставленных файлов csv ...
Здравствуйте, Аноним, Вы писали:
А>Здравствуйте, Kore Sar, Вы писали:
А>>>Доброе ....
А>>>Что вы делаете с этими данными? Если льете в базу — посмотрите в сторону bulk...
KS>>Не льём. Мы их считаем. Статистика и всё такое...
А>Доброе ... А>Для объемов данных, которые вы представили — имхо имеет смысл обратить взор в сторону субд... А>Oracle (sqlldr) и MsSql (bcp) — имеют средства для массовых вставок ... А>Для бесплатных субд можно посмотреть наличие этой опции... А>Опять таки функционал по агрегации есть в самой субд ...
А>Я так понимаю у вас руки не связаны по постобработке предоставленных файлов csv ...
У нас Оракл. И мы вот уже второй год уговариваем наших менеджеров (которые сидят далеко за бугром) сделать аггрегирование данных прямо в СУБД.
Но, т.к. это займёт уж очень много времени, то мы этого не делаем.
Здравствуйте, Kore Sar, Вы писали:
KS>У меня пробел в знаниях. KS>Что это? — "использовать кольцевой буфер, либо со сдвигом остатка строки в начало при достижении конца строки" KS>Можно ссылками.
Простейший и быстрейший парсер CSV в ASCII будет выглядеть примерно так: (обработка ошибок здесь отсутствует в принципе)
static IEnumerable<byte[][]> ParseCSV(byte[] data, int fieldCount)
{
int[] fieldPositions = new int[fieldCount + 1];
var currentField = 0;
var comma = toByte(',');
var cr = toByte('\n');
fieldPositions[currentField++] = 0;
for (var position = 0; position < data.Length; position++)
{
var sym = data[position];
if (sym == comma)
{
fieldPositions[currentField++] = position + 1; // skip ','
}
else if (sym == cr)
{
byte[][] result = new byte[fieldCount][];
fieldPositions[currentField] = position;
for (int i = 0; i < fieldCount; i++)
{
var length = fieldPositions[i + 1] - fieldPositions[i] - 1;
var field = new byte[length];
Array.Copy(data, fieldPositions[i], field, 0, length);
result[i] = field;
}
currentField = 0;
fieldPositions[currentField++] = position + 1; // skip lfyield return result;
}
}
}
private static byte toByte(char c)
{
return Encoding.ASCII.GetBytes(new[] {c})[0];
}
static void Main(string[] args)
{
var testCsv = @"1,3,4,5
6, 7, 8, 9
10a, 123 bb b , sadfasdf , asdfsadf
";
var testData = Encoding.ASCII.GetBytes(testCsv);
foreach (var row in ParseCSV(testData, 4))
{
Console.WriteLine("Row -> {0}",
String.Join(":", row.Select(b => Encoding.ASCII.GetString(b)).ToArray()));
}
}
Для работы с потоком нужно работать не со всеми данными, а с буфером. Для этого требуется чтобы одно поле всегда находилось в буфере полностью либо склеивать его из кусочков. Для первого случая применяется кольцевой буфер, он требует больше памяти чем обычный (как минимум maxFieldSize * 2), данные читаются в него кусками по maxFieldSize поочередно в первую и вторую половину. При работе с кольцевым буфером алгоритм почти не требует переделки, кроме адресации данных (вместо position используем position % buffer.Length) и обработки ситуации где начало поля в конце буфера, а конец в начале.
Здравствуйте, Kore Sar, Вы писали: S>> Еще можно использовать BitArray Что бы отсеивать символы ',' и '\r' и '\n'
KS>У меня пробел в знаниях. KS>Что это? — "использовать кольцевой буфер, либо со сдвигом остатка строки в начало при достижении конца строки" KS>Можно ссылками.
KS>И, да, я уже говорил, что у нас чистый ASCII. Никаких 1251.
Кольцевой буфер это фиксированный массив где индекс начало строки может быть больше индекса конца строки.
Пример Queue.
При достижении конца считанных данных, новые данные считываются до конца буфера и с начало буфера до начала строки.
Сдвиг остатка строки в начало, тоже использует, фиксированный массив, но для того что бы начало строки было всегда меньше конца,
То есть при достижении конца буфера, неполная строка сдвигается в начало и данные считываются от конца строки в конец буфера.
Тогда проще модифицировать StreamReader.readLine, но обрабатывать байты а не чары с использованием BitArray.
Ссылок уже и не помню.
Вот пример кольцевого буфера правда на Delphi
unit TextReader;
interface
Uses Classes,SysUtils;
Const TextBuferSize=$10000;
TextBuferSizeMaxIndex=TextBuferSize-1;
Type
TTextReader= Class
Private
FStream:Tstream;
Buffer:Array[0..TextBuferSizeMaxIndex] of char;
DelemiterSet:Set of Char;
EndBuffer,BeginString,EndString,CurrentPos:Integer;
FEof:Boolean;
Protected
Procedure CheckDelemiter;
Function GetCurrentString:String;
Procedure ReadFromStream;
Function CanRead:Boolean;
public
Constructor Create(FileName:String);
Destructor Destroy; override;
Procedure Readln;
Property CurrentString:String read GetCurrentString;
Property Eof:Boolean read FEOF;
end;
implementation{ TTextReader }function TTextReader.CanRead: Boolean;
begin
Result:= FStream.Position<Fstream.Size;
end;
procedure TTextReader.CheckDelemiter;
begin//If CurrentPos=EndBufferend;
constructor TTextReader.Create(FileName: String);
begin
Fstream:=TFileStream.Create(FileName,fmOpenRead or fmShareDenyWrite);
EndBuffer:= Fstream.Read(buffer[0],TextBuferSize)-1;
FeOf:=(EndBuffer=-1);
If Not FEof Then
FEof:=(buffer[0]=#0);
DelemiterSet:=[#0,#10,#13];
BeginString:=0;
EndString:=0;
CurrentPos:=0;
end;
destructor TTextReader.Destroy;
begin
If Assigned(Fstream) Then Fstream.Free;
inherited;
end;
function TTextReader.GetCurrentString: String;
Begin
If BeginString=-1 Then
Begin
Result:='';
Exit;
end;
// If EndString=BeginString Then
// Result:=buffer[EndString]
// elseIf EndString>=BeginString
Then
Begin
SetLength(Result,EndString-BeginString+1);
Move(buffer[BeginString],Result[1],Length(Result));
end
Else
Begin
SetLength(Result,TextBuferSize-BeginString+EndString+1);
// FillChar(result[1],Length(Result),0);
Move(buffer[BeginString],result[1],TextBuferSize-BeginString);
Move(buffer[0],result[TextBuferSize-BeginString+1],EndString+1);
end;
end;
procedure TTextReader.ReadFromStream;
begin
If BeginString=-1 Then
Begin
EndBuffer:=Fstream.Read(buffer[0],TextBuferSize)-1;
CurrentPos:=0;
Exit
end;
//-------------------If EndBuffer=TextBuferSizeMaxIndex Then
Begin
If BeginString=0 Then Raise Exception.Create('Слишком длинная строка');
EndBuffer:= Fstream.Read(buffer[0],BeginString)-1;
end//-------------------else If BeginString<=EndBuffer Then//---------------------------Begin
EndBuffer:=EndBuffer+ Fstream.Read(buffer[EndBuffer+1],TextBuferSize-EndBuffer-1);
end//---------------------------else//------------------------------------------Begin
If BeginString=(EndBuffer+1) Then Raise Exception.Create('Слишком длинная строка');
EndBuffer:=EndBuffer+Fstream.Read(buffer[EndBuffer+1],BeginString-EndBuffer-1);
end;
//------------------------------------------end;
procedure TTextReader.Readln;
begin
BeginString:=-1;
If Not (Buffer[CurrentPos] in DelemiterSet) Then
BeginString:=CurrentPos;
While Not (Buffer[CurrentPos] in DelemiterSet) Do
Begin
If CurrentPos=EndBuffer Then
ReadFromStream;
CurrentPos:=(CurrentPos+1) mod TextBuferSize;
End;
If CurrentPos=0 Then
EndString:=TextBuferSizeMaxIndex
else
EndString:=CurrentPos-1;
If Buffer[CurrentPos]=#0 Then
Begin
FEof:=True;
exit;
End;
If CurrentPos=EndBuffer Then//----------------------------------If self.CanRead Then
Begin
ReadFromStream;
end
Else
Begin
FEof:=True;
exit
end;
CurrentPos:=(CurrentPos+1) mod TextBuferSize;
If Buffer[CurrentPos]= #10 then
Begin
If CurrentPos=EndBuffer Then//----------------------------------If self.CanRead Then
Begin
ReadFromStream;
end
Else
Begin
FEof:=True;
exit
end;
CurrentPos:=(CurrentPos+1) mod TextBuferSize;
If Buffer[CurrentPos]=#0 Then
Begin
FEof:=True;
exit;
End;
end;
end;
end.
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Serginio1, Вы писали:
S> Тогда проще модифицировать StreamReader.readLine, но обрабатывать байты а не чары с использованием BitArray.
Про буфер ясно. А вот чем тут поможет BitArray и как его заюзать — это не ясно.
(И, да, я знаю что такое BitArray.)