A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

© admin 程序媛   /  2011-7-14 11:43  /  21913 人查看  /  16 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

Java API中没有提供删除文件中某一行的函数。

传统的实现方法是利用BufferedReader一行行读出数据然后放入List集合,最后重新写进去文本,碰到要删除的行就跳过.这种解决方案碰到数据量小的文本没有问题。

但是我现在要对几百万行的文本操作。这种办法肯定行不通。这个文本里面的存放着几百万条sql语句,狂晕中。。。   我现在要实现的是,读出一条语句,执行sql,然后删除这条语句,继续执行下一条,删除,继续....  

问题我已经提出来了,只要能解决问题。不管你是告诉我思路,还是其他解决方案,我狂感谢你!!

《《此题给10分》》

16 个回复

倒序浏览
黑马网友  发表于 2011-7-14 12:19:12
沙发
1. readLine()循环读出每一行数据   
2. 创建一个新的文件
3. 匹配要删除的那一行  
     如果找到了,删除;  
     如果不匹配,则将当前行写入新文件。

评分

参与人数 1技术分 +1 收起 理由
admin + 1 楼板抢得快,给1分

查看全部评分

回复 使用道具 举报
黑马网友  发表于 2011-7-14 12:58:07
藤椅
不把读取的数据放到List集合中,直接放到另一个文件中,这个文件和之前的源文件名相同,但是不放在同一个地方,等执行完之后,再把这个新文件复制过来覆盖掉原来的文件。
回复 使用道具 举报
黑马网友  发表于 2011-7-14 12:58:20
板凳
利用RandomAccessFile类,读取要删除的sql语句,在前面加上注释符(--)。
好吧,我真的想不到办法删除某行。。。
回复 使用道具 举报
黑马网友  发表于 2011-7-14 13:52:13
报纸
在解惑RandomAccessFile时发现的。。希望对你有帮助用。
[url]http://www.ibm.com/developerworks/cn/java/l-javaio/[/url]
回复 使用道具 举报
黑马网友  发表于 2011-7-14 14:05:56
地板
我也发发想法思路
首先文件太大,应该用RandomAccessFile来分段读取。
1、用RandomAccessFile读出文件的某一段。
2、内容用split以/r/n分取出各行。记下当前段最后一行的开始位置(当前段的长度-split后最后一个数组元素的长度,ps:中间可能需要校证处理,比如碰到当前段结尾刚好是/r/n或多个/r/n的情况)
3、依次执行每一行,最后一行不执行,因为可能不完整,所以需要把最后一行和一次读取的段整合后再slipt再执行。 只有读取到文件最最后一段时,才执行最后一行。
4、又走第1步读取读执行,直到文件读完或操作结束。
5、最后结束操作时,再从记录的seek处读取剩下的文件,再写出来就,就等删除掉了所有执行过的行。

评分

参与人数 1技术分 +3 收起 理由
admin + 3 有戏!!!!

查看全部评分

回复 使用道具 举报
黑马网友  发表于 2011-7-14 14:15:05
7#
每一行都必须以“#”开头。 
public void parseFile(Readerreader)throws IOException{
  LineNumberReader in = new LineNumberReader(reader);
  Stringline="";
  while((line=in.readLine())!=null){
  if(line.startsWith("#")){
  //处理
  ...
  }else{
  thrownew IOException(""}
  }
  in.flush();
  in.close();
  }
这样我们就能每一次readLine(这个也是从文件的第一行开始往下读的),然后判断,再进行文件的存取。
回复 使用道具 举报
ccxztian 黑马帝 2011-7-14 15:05:58
8#
这个思路看能行不?
1建立同大小空文件一份,读出原来文件中要删除的内容,记录其原来处在的行数号(如果源文件存储格式不规范那记录其语句在文件中的开始相对地址和结束相对地址),将其写入新建文件同相对地址处。
2需要删除的语句全部读取复制完后,两文件进行与操作。

PS:java api还不熟悉,不清楚查找的效率如何,单纯查找的话可根据文件中存储的语句的特点建立多级索引,提高效率。

评分

参与人数 1技术分 +1 收起 理由
admin + 1 效率上肯定有问题,给1分吧

查看全部评分

回复 使用道具 举报
黑马网友  发表于 2011-7-15 16:43:56
9#
输入流FileInputStream和输出流 FileOutputStream,实现的是对磁盘文件的顺序读写,而且读写要分别创建不同对象。RandomAccessFile类则可对文件实现随机读写操作。

·新建RandomAccessFile对象的文件位置指针位于文件的开头处;

·每次读写操作之后,文件位置的指针都相应后移到读写的字节数;

·可以通过getFilePointer方法来获得文件位置指针的位置,通过seek方法来设置文件指针的位置。
用skip( )//跳过方法,但在读取的过程中,前面的字节都被删除掉了

   这个怎么样
回复 使用道具 举报
黑马网友  发表于 2011-7-15 19:45:46
10#
首先我们要查找的这条要删除的语句,我们知道要删除的是什么,所以我们写一个find类来定义一个查找方法,然后可以用判断的方法来读取文本中的方法,如果第一个字符和要删除的第一个字符一样保存到数组中,标记位置,然后继续读下一个字符, 这样我们就可以判断出这个字符串是不是我们要删除的一条语句了,然后 删除  我们读到的标记长度 减去 标记的总长度。就能得到这句要删除的语句了,通过SQL语句把这句话删除。。然后继续从标记的最后一个点 开始读文件,只到读完位置。

这样的效率也同样会很慢,因为 我想的还是从头读到尾 仅仅是把没用的跨过去了,
这时候 我就考虑到了 用数据结构的 分块查找法,首先将我们要索引的文本分成若干的子表,这时候问题又出现了,因为在分块的时候,我们很有可能把要删除的语句给分解开,所以用分块查找法的时候,必须要有一种算法考虑到的是分块的长度多少能使我们删除的语句不被拆分。

不知道想法 对不对,希望有用。你这种题 就得学好数据结构,没有很强的算法基础,就得多走很多路。就好像没有好的坐骑一样,肯定会慢于别人。
回复 使用道具 举报
黑马网友  发表于 2011-7-25 09:35:20
11#
执行一条删一条? 那倒不如执行完所有的sql语句后,把整个文件给删掉算了。
听了您的描述,看样您确实是打算,要一次性执行完所有的sql语句。
“读出一条语句,执行sql,然后删除这条语句,继续执行下一条,删除,继续....   ” 省略号可以给我作证明。


需求好像没说清楚啊。
回复 使用道具 举报
黑马网友  发表于 2011-7-25 10:04:48
12#

回复 楼主 的帖子

void cut(int startIndex,
         int endIndex)将两个索引之间的文本剪切到系统剪贴板中。

参数:
startIndex - 文本中的起始索引
endIndex - 文本中的结尾索引
回复 使用道具 举报
读入某一行后,将这一行替换为空,写入原文件,当此行内容被覆盖后抛出异常强制关闭文件
回复 使用道具 举报
黑马网友  发表于 2011-7-25 10:28:10
14#
我想是不是可以这样做,将执行和删除分开.
1 建立俩个新文件,用来纪录行号或文件指针的位置
2在原文件中查找,是否是要执行的行,如果是则纪录行号存放在一个文件中,过不不适则存放在另一个文件中
3这个步可以考虑是否能用到多线程来分别将,分别去执行语句并将要保留的行放在一个临时文件中去.
4 将需要保留的数据重新写入原文件.
回复 使用道具 举报
如果用RandomAccessFile来读取文件的话
想到了几种方法,我现在电脑配置低,也没有安装环境什么的,所以没有条件去试试,希望各位指正哈:)
一、我们定义一个竹筒一次性读取所以的数据[code=java]byte[] strValue = new byte[(int)file.length()];[/code]1、扫描源文件,到达删除行,获得删除行首的文件记录指针位置getFilePointer();
2、获得删除行下一行首文件记录指针位置getFilePointer();
3、将指针设置在2出所得的位置读取后面的数据
4、把指针定在1所得的位置进行保存数据,会对原始数据进行覆盖
二、扫描源文件,到要删除的行尾,因为我们知道对于一个文本文件如果直接存储数据是会覆盖原来的数据的
对此想到我们可以对这一行要删除的数据行的头尾各插入一个标记,再对这个文件进行读取,对数据里面的标识进行匹配
对这两个标识中的数据用replace替换成""
三、这个肯能就要创建一个临时的文件来保存读取的数据,前面几位也讲到了
四、讲文本文件按行存到一个byte[]数组里面,对于要删除的行所对应数组里面的元素直接替换成空格[code=java]1.File file = new File("c:/itcast.txt");//创建读取原
BufferedReader reader = new BufferedReader(file);//定义包装流
byte[] strValue = new byte[(int)file.length()];//定义一个读取的水桶,一次性读取全部数据
String str = reader.read(strValue);//按文件大小一次读入
String rows = str.split("\r\n");//按换行符拆分,即数组的每一条,对应文件每一行的内容。
//如果要删除按条件删除某一行,只需要判断字符串数组是否存在这一行了,如果存在,替换为“”即可。
Writer writer = new FileWriter(file);
for(int i=0;i<rows.length;i++){
  writer.write(rows);
}[/code]
[ 本帖最后由 詹季春 于 2011-07-25  11:29 编辑 ]
回复 使用道具 举报
黑马网友  发表于 2011-7-25 13:57:47
16#
在java解析xml的方式中有SAX方法,它是对xml文档一条一条读入内存的,只要实现了JAXP接口就可以了。所以很简单的方法就是将sql语句写成xml文档,利用java对xml的读写进行操作
回复 使用道具 举报
黑马网友  发表于 2011-7-25 15:35:59
17#

回复 楼主 的帖子

个人观点  貌似只有这么做了
         假设要读入的文件是x.txt
                  y.txt作为处理过的文件
          InputStream in = new FileInputStream("x.txt");
        BufferedReader br = new BufferedReader(new InputStreamReader(in));
               
        OutputStream out = new FileOutputStream("y.txt");
        PrintWriter pw = new PrintWriter(out);
                    String  s0 = "所要删除的语句";
                                        for(;;)
                {
                        String s = br.readLine();
                                                            if(s == s0)
                                                                       continue;
                        if(s==null) break;
                       
                                   pw.println(s);
                }
                pw.flush();
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马