注册 登录
编程论坛 Delphi论坛

请教.CSV记录文件的读取问题

yalewang 发布于 2010-07-10 21:34, 4220 次点击
只有本站会员才能查看附件,请 登录
我有一个.CSV文件,数千行,且实时增加,每行长度一样,想读取其中的数据,再利用第二列的数据画图线。
我的方法是读取最后一行数据,然后存入数组,可是读取不出数据望高手指教。
数据格式如下:(附件有一.CSV文件)
 1278450011;1.25860000
 1278450012;1.25850000
 1278450015;1.25860000
 1278450016;1.25850000
 1278450018;1.25860000
 1278450031;1.25850000
 1278450036;1.25860000
 1278450036;1.25850000
 1278450037;1.25860000
 1278450039;1.25870000
 1278450045;1.25860000
两数据中间是分号,也可以是空格。
我的读取代码如下:
type
  jilu=record
  shi:longint;
  fenhao:string[1];
  jia:double;
  end;


var
  ffile: file of jilu   ;
  d:jilu;

procedure TForm1.Button1Click(Sender: TObject);
begin
assignfile(ffile,'E:\EE.csv');
reset(ffile);
Seek(ffile,FileSize(ffile) div (21)-1);//将指针移到最后一行,每行的字符数是21
read(ffile,d);
 ShowMessage(d.shi);
 listbox1.Items.Add('shi:'+d.shi);
 listbox1.Items.Add('fenhao:'+d.fenhao);
 listbox1.Items.Add('jia:'+d.jia);
CloseFile(ffile)  ;
end;
11 回复
#2
东海一鱼2010-07-10 22:45
结构定义错误,数据全是AscII字符。你不转换,哪里来的longint和double。
Seek(ffile,FileSize(ffile) div (21)-1);//将指针移到最后一行,每行的字符数是21
这可未必,你漏算了回车换行字符($0d$0a);

给你个超简单的:
procedure TForm1.btn1Click(Sender: TObject);
var
  CsvData: TStringList;
  I: Integer;
begin
  CsvData:= TStringList.Create;

  try
    CsvData.LoadFromFile('ee.csv');
    for I := 0 to CsvData.Count -1 do
    begin
      mmo1.Lines.Add(Pchar(CsvData.ValueFromIndex[I]) + 11);
    end;
  finally
    CsvData.Free;
  end;  

end;

[ 本帖最后由 东海一鱼 于 2010-7-10 23:45 编辑 ]
#3
yalewang2010-07-11 00:12
多谢回复,关于行数的问题,我用文件的字符总数手工除了一下.CSV文件的总行数,得出一个记录有24个字节,不是21.
你的程序能否加上控件的添加说明,本人初学,不知mmo1是哪一个控件,我只改了button1的name和caption为btn1。
另外,如定义正确的结构,应该怎样做?
#4
东海一鱼2010-07-11 09:25
mmo1: TMemo;

关于定义正确的结构,我是这样看:
如果你的文件是二进制的,定义一个对应的数据结构才有意义。而对一个纯文本文件来说,结构似乎无意义。
如果硬要定义的话:

type
  jilu=record
    CvsLineData: array[0..20] of char;
  end;
可能比较符合文件特征。

以上个人看法,仅供参考。


#5
yalewang2010-07-11 09:41
请问一下,用上述方法读写和用流方法读写及数据库方式,哪一个快一些?
谢谢
#6
yalewang2010-07-11 09:52
控件已装好。
#7
yalewang2010-07-11 09:57
试过了,又调了参数试,OK
#8
yalewang2010-07-11 10:23
我将for I := 0 to CsvData.Count -1 do
    begin
      mmo1.Lines.Add(Pchar(CsvData.ValueFromIndex[I]) + 11);
.....
改成了
      mmo1.Lines.Add(Pchar(CsvData.ValueFromIndex[CsvData.Count -1]));

来读取最后一行,结果是1278685775;1.26960000和原记录一样
现在想将结果从分号处分割成前后两个数据,分别存入两个数组array1[1..20]和
array2[1..20]的array1[1]、array2[1]   能否帮我调整一下。
多谢
#9
东海一鱼2010-07-11 15:17
恭喜。

数据流方式是最快的,其次是数据库方式(单机,网络的话要看网络通讯质量)。文本存储是最慢的。唯一的优点就是易读性。

Pchar(Pchar(CsvData.ValueFromIndex[I]) + 10)^:= char(0);
lstrcpy(array1,Pchar(CsvData.ValueFromIndex[I]));
lstrcpy(array2,Pchar(CsvData.ValueFromIndex[I]) + 11);
#10
yalewang2010-07-12 09:19
对不起,我表述的不清楚,是将记录分成两部分存入两个字符串数组。(我以后通过其他方法保存后20个记录的值。)
对指针、字节(字符)数组操作、转换我很难理解。
var
array1:array[1..20] of string;
array2:array[1..20] of string;


[ 本帖最后由 yalewang 于 2010-7-12 09:21 编辑 ]
#11
东海一鱼2010-07-12 13:01
procedure TForm1.btn1Click(Sender: TObject);
var
  CsvData: TStringList;
  Arry1,Arry2: array[0..20] of Char;                       //两个字符串数组,用来保存结果
begin
  CsvData:= TStringList.Create;

  try
    CsvData.LoadFromFile('d:\ee.csv');

    lstrcpyn(Arry1,PChar(CsvData.Strings[CsvData.Count - 1]),11);            //拷贝最后一行的前10个字符。
    lstrcpyn(Arry2,PChar(CsvData.Strings[CsvData.Count - 1]) + 11,11);       //拷贝最后一行的从第12个字符开始的10个字符。
    mmo1.Lines.Add(Arry1);                                                   //输出结果。
    mmo1.Lines.Add(Arry2);
  finally
    CsvData.Free;
  end;
end;

我昨天也犯了个大错误,Pchar(Pchar(CsvData.ValueFromIndex[I]) + 10)^:= char(0);这句本意是想将一行的原始数据中分,可犯了大忌。
因为这样会使delphi的字符串分配回收函数出错。
#12
yalewang2010-07-12 14:30
你好棒,我运行了一下,完全读出了数据。第一个数据前多了一个空格。
加到定时器中完全同步。
lstrcpyn(Arry1,PChar(CsvData.Strings[CsvData.Count - 1]),12);   
lstrcpyn(Arry2,PChar(CsvData.Strings[CsvData.Count - 1]) + 12,11);
再次感谢。
1