最近由于要分析log,但是由于log文件太大而不能用编辑器打开所以学要分割文件。
于是想了两三个方法。
1,shell命令分割。没找到。那位达人了解的给个提示啊。
2,软件分割。免费软件不能分割大文件。
3,程序分割。关于3,我写了一段程序。
想当然的我用RandomAccessFile读文件,然后用FileOutputStream输出。
发现效率十分低下。3g文件 500m一个,文成一个就将近3分钟。
于是改成了如下形式FileInputStream in = new FileInputStream(srcFile);
FileChannel channel = in.getChannel();
FileOutputStream out = new FileOutputStream(fileSeparateName);
FileChannel outChannel = out.getChannel();
channel.transferTo(beginPos, blockSize, outChannel);
这样一来速度有了明显提升。但是在分割小文件(几十M)时速度又不如第一个方法。于是产生了下面的疑惑。
1,在什么样的情况下channel要好于stream.有没有具体的临界点。
2,从这个情况来看 java 的io 在不同的情况下可能要使用不同的类组合来达到最好的效率。哪个达人可以指点一下。或者大家来讨论一下啊。
于是想了两三个方法。
1,shell命令分割。没找到。那位达人了解的给个提示啊。
2,软件分割。免费软件不能分割大文件。
3,程序分割。关于3,我写了一段程序。
想当然的我用RandomAccessFile读文件,然后用FileOutputStream输出。
发现效率十分低下。3g文件 500m一个,文成一个就将近3分钟。
于是改成了如下形式FileInputStream in = new FileInputStream(srcFile);
FileChannel channel = in.getChannel();
FileOutputStream out = new FileOutputStream(fileSeparateName);
FileChannel outChannel = out.getChannel();
channel.transferTo(beginPos, blockSize, outChannel);
这样一来速度有了明显提升。但是在分割小文件(几十M)时速度又不如第一个方法。于是产生了下面的疑惑。
1,在什么样的情况下channel要好于stream.有没有具体的临界点。
2,从这个情况来看 java 的io 在不同的情况下可能要使用不同的类组合来达到最好的效率。哪个达人可以指点一下。或者大家来讨论一下啊。
不過如果條件允許的話
你可以大概判斷下小于100用stream不然用channel
Reader/Writer和FileChannel在文本读写上都不错,后者是jdk文档里推荐使用的,据说jdk1.6中io性能有很大提升喵`~~`
也就是说,你整个处理条目的逻辑会复杂,速度会有一些影响。LineNumberReader lnr = new 你应该用这个,我觉得这是你应该用的类。而且文件读取,你把内容全部存放到内存里,是不可避免的,以前我分析日志的时候,恐怕比你做的日志要多得多。
Java还是能勉强应付的,。
一天的日志都会打成gz文件。不过拿到本地打开的话就是3g了,这个没办法啊。
我也想小一点啊。谢谢甘草 的建议 我会再去查一下LineNumberReader的。关于日志的分析,不知道大家都是如何做的。
我现在是客户那边在出错之后告诉我时间和错误摘要。
然后我从日志里分析。这样的话只要几个时间点的日志就好了。也就是分割之后
我grep一下 找到目标打开文件直接看日志,分析错误。不知道火龙果前辈所说的分析是怎样的分析啊?
我还很菜 希望大家多多指点
1,我需要分析的一般是一个时间点前后的日志。比如8点10分出错那么我只想看
8点到8点10分的日志。这样的话是不是一行被截断并不是大问题。
但如果先搜索再截断那么在内存的操作会很费时间。所以我选择直接阶段然后用工具搜索。
2,即使我按照一个完整行必须在一个文件里,对我的日志来说也没有意义。
因为我经常看见sql问里面就错行了。这样的化一个sql其实有的可以占好多行。到时候还是不便。
而且读入内存的运行时间对于紧急对应实在是太长。因为一个对应可能只给你2,3个小时。
读日志就近20分钟的话,太长了。谢谢 火龙果 甘草的指正
去粗取精,适合Python或者C++这样的程序写,逻辑不多,只是重点在IO上。
我的工作就是找错误
vm console 页面的日志都小,sql很头疼,所以要分割一下。查了一下LineNumberReader,跟有用的一个类。
JAVAIO 从来就没学好那位大师总体给讲一下就好了
您说的去粗取精这个过程,现在的java和c++差距很大吗?
另外对于本来应该在一行的数据结果不一定在一行上的情况如何处理的呢?
尽量用C++和Python脚本出来最初的log文件,把没用的东西去掉。
所谓decorator,装饰,其实可以说是一种设计的技巧,说白了没什么难的,别看很多网上资料说的天花乱坠的(非常讨厌有些文章总是把简单的问题描述得跟两头猪的kiss问题一样复杂……)。decorator的结构如下: MyInterface
|
_______|_______
| |
Myclass Decorator
____|_____
| |
DecoratorA DecoratorB
decorator的目的是在不改变任何原有的类的基础下,添加新的功能(你可以理解为书上说的灵活性)。其中Myclass是你要扩展的类,DecoratorA跟DecoratorB封装了你要扩展的功能,并保存有一个MyInterface的引用。考虑以下代码:
public static void main(Strings[] arg){
myInterface a = new myClass();
a.print();
}
myInterface 是myClass的接口,只声明了一个方法print(),myClass实现了该方法:public void print(){
System.out.println("hello");
}那么假如我们要在不改变原来的myClass的基础上,变成输出“hello world!”,要怎么做呢?
当然我们可以考虑直接写个myClass的子类,helloClass之类,但是要是要求根据环境不同,输出"hello world!",my hello world","my Hello"之类的组合呢?
用继承的方式将不得不写一堆类似的子类来。decorator,装饰模式的解决方法是,只实现基本的功能,把附加的功能抽出来放一边。
例如以下代码:
class DecoratorA implements Decorator{
MyInterface myObject;
DecoratorA(myInterface myObject){
this.myObject = myObject;
}
public void print(){
myObject.print();
System.out.print("world!");
}
}class DecoratorB implements Decorator{
MyInterface myObject;
DecoratorA(myInterface myObject){
this.myObject = myObject;
}
public void print(){
System.out.print("my");
myObject.print();
}
}
DecoratorA和DecoratorB的功能分别是打印出world跟my。这时main函数要打印出my hello world可简单变为:public static void main(Strings[] arg){
MyInterface a =new DecoratorA(new DecoratorB(new MyClass());
a.print();
}简单吧?简单的说,就是:
print(){
print("xxx");//可替换成你要添加的任何处理;
myObject.print();//调用基础类的函数;
xxxx; //后续处理
}
Decorator的介绍就到此为止,接下来讲java.io.看到MyInterface a =new DecoratorA(new DecoratorB(new MyClass());是不是觉得眼熟咧?这跟BufferedInputStream bis = new BufferedInputStream(new DataInpuStream(new FileInputStream("xxx.txt")));是不是很像?(画外音加一个臭鸡蛋扔上来:因为java.io就是用decorator模式组织的,当然像啦……)java.io分Stream跟reader、writer两大类,这里只详细介绍Stream,并最后两者间的关系。Stream又分inputStream、OutputStream,两者基本是对称的,这里也只介绍InputStream. java.io.InputStream
|
_______________________|________________________
| |
ByteArrayInputStream FilterInputStream
StringBufferInputStream _____________________|_________________
FileInputStream | | | |
PipedInputStream DataInputStream BufferedInputStream LineNumInpuStream XXX(注:xxx是PushbackInputStream,上面的图放不下)这个图跟最初介绍的hello world的图很像吧?呵呵。
基础的流只有左边4个,这些流代表了数据的来源,所有的流都必须从这四个中之一开始。(注,还有一个RandomAccessFile、File,这两个不在本文介绍范围)。
然后当我们需要什么添加功能,就从右边中选择一个装饰。例如,我们需要缓存功能,那么需要bufferedInputStream装饰:BufferdInputStream is = new BufferedInputStream(new FileInputStream("xxx.txt"));假如再要DataInputStream的功能,只要在加一层:
DataInputStream dis = new DataInputStream(new BufferdInputStream(new FileInputStream));
(厄,我不甚明白这个类添加的功能是做什么用的,资料说是增加读取java原生数据的功能,不甚明白,有清楚的来补充一下,pipeInputStream跟sequenceInputStream也没用过,欢迎补充说明)
这里你可以想象成,在基本的FileInputStream.readxxx()方法在BufferedInputStream的readxxx()方法调用,并添加相应的处理。
我这里没有c++编译环境。Python又不会。
vb效率如何? c应该也可以吧,还有不知道shell 直接作效率如何。
谈谈感受吧!
BufferedInputStream fis = new BufferedInputStream(new FileInputStream(file),10*1024*1024);
// 用10M的缓冲读取
Python的安装太简单了,下一个,然后是下一步,下一步,下一步,下一步,下一步,完成,就可以了。
的确问题最初是在不能打开大文件上。但是在用程序分割文件时想到了一些问题提出来大家讨论一下。
ultraEdit好像需要注册的啊。即使能打开也是不好的。如果将3g文件写到内存和缓村里那么机器可能就非常慢了。
读出一行
是否大于等于指定时间范围的下限?
是:
是否小于指定时间范围的上限?
是:写文件
否:停止写文件,跳出循环结束
否:
返回上面接着读
}
BufferedReader 的默认缓冲区好像是8192把,如果想增加缓冲区我
觉得用BufferedInputStream fis = new BufferedInputStream(new FileInputStream(file),10*1024*1024);
比较好
你说的方法不错。我用vb实现过类似的但感觉时间点不好定,就没怎么再用。因为grep速度还是不错的。
发这个帖其实是有私心的,并不是单纯解决问题。因为自己对java 的 io感觉很不了解。所以想跟大家学习一下。提高自己啊。TO' taojy
上下翻页对调查不是很好,因为要反复看。所以还是记录下来比较好啊。我觉得。
我认为,读取文件并不需要增加缓冲区,有 8kB 差不多够用了(节约内存呗),
当然要增加到 10MB 也可以啊,这样或许会更快一些,没有试验过。
这样 EditPlus 就可以打开一个文件了。
呵呵,Global Regular Expression Print, grep
这个工具估计是没有办法再优化了。
现在六台机器作managed server 一小时一个的话一天就是6*24啊
光找log也挺累得 呵呵。
________________不会玩游戏,看不懂,55555~~
[size=30px]哈哈,o(∩_∩)o[/size]
如果谁看见已经有翻译好的告诉我啊 我就不写了 呵呵原文
http://java.sun.com/developer/technicalArticles/Programming/PerfTuning/摘要翻译IO性能java总是假定只有两种文件组织形式。
第一种,基于字节流(stream of bytes)
第二种,基于字符序列(character sequences)java 中一个字符有两个字节。所以在从文件读字符时需要转换。提高io性能的基本原则
1,尽量避免访问磁盘
2,尽量避免访问OS
3,尽量避免方法调用
4,尽量避免单独处理字节或字符下面通过一个计算换行数的例子来说明这些原则是如何被应用的。1,读
import java.io.*;
public class intro1 {
public static void main(String args[]) {
if (args.length != 1) {
System.err.println("missing filename");
System.exit(1);
}
try {
FileInputStream fis =
new FileInputStream(args[0]);
int cnt = 0;
int b;
while ((b = fis.read()) != -1) {
if (b == '\n')
cnt++;
}
fis.close();
System.out.println(cnt);
}
catch (IOException e) {
System.err.println(e);
}
}
}
这段代码中频繁调用了OS 函数,也就是FileInputStream.read
一个本地方法负责读取文件的下一个字节。2,采用大缓存import java.io.*;
public class intro2 {
public static void main(String args[]) {
if (args.length != 1) {
System.err.println("missing filename");
System.exit(1);
}
try {
FileInputStream fis =
new FileInputStream(args[0]);
BufferedInputStream bis =
new BufferedInputStream(fis);
int cnt = 0;
int b;
while ((b = bis.read()) != -1) {
if (b == '\n')
cnt++;
}
bis.close();
System.out.println(cnt);
}
catch (IOException e) {
System.err.println(e);
}
}
}
BufferedInputStream.read从缓存中读取字节。减少了底层api访问。3,直接缓存
我们不使用BufferedInputStream 而是自己直接缓存。
这样可以减少方法调用。 import java.io.*;
public class intro3 {
public static void main(String args[]) {
if (args.length != 1) {
System.err.println("missing filename");
System.exit(1);
}
try {
FileInputStream fis =
new FileInputStream(args[0]);
byte buf[] = new byte[2048];
int cnt = 0;
int n;
while ((n = fis.read(buf)) != -1) {
for (int i = 0; i < n; i++) {
if (buf[i] == '\n')
cnt++;
}
}
fis.close();
System.out.println(cnt);
}
catch (IOException e) {
System.err.println(e);
}
}
}对于1m的文件 执行时间分别是
intro1 6.9
intro2 0.9
intro3 0.4最慢的和最快的时间比是 17 比 1当然这并不是说我们总是要采用第三种方式。
其实第三种方式可能产生错误,特别是在处理end-of-file事件时(要仔细处理这类事件).
并且它可读性比较差.但是作为一个方法还是应该引起我们的注意.第二种方式可能是最普通的方式.
【缓存】
第二种和第三种方式都用到了缓存.它确实是提高IO速度的基本手段。
这很容易让我们想起一个问题。是不是缓存越大IO越快。
JAVA 的缓存默认一般是1024 或 4048 比特。
更大的缓存可能加快IO但是也就是5% 10% 左右的小幅提升。4,整个文件读取 import java.io.*;
public class readfile {
public static void main(String args[]) {
if (args.length != 1) {
System.err.println("missing filename");
System.exit(1);
}
try {
int len = (int)(new File(args[0]).length());
FileInputStream fis =
new FileInputStream(args[0]);
byte buf[] = new byte[len];
fis.read(buf);
fis.close();
int cnt = 0;
for (int i = 0; i < len; i++) {
if (buf[i] == '\n')
cnt++;
}
System.out.println(cnt);
}
catch (IOException e) {
System.err.println(e);
}
}
}
这样很方便但也有很明显的不足,内存是不是比文件大。另外一个缓存的关注点是向终端的输出。SYSTEM.OUT默认是行缓存,
也就是说缓存在遇到一个换行符的时候会将内容强行输出。5,阻止行缓存
import java.io.*;
public class bufout {
public static void main(String args[]) {
FileOutputStream fdout =
new FileOutputStream(FileDescriptor.out);
BufferedOutputStream bos =
new BufferedOutputStream(fdout, 1024);
PrintStream ps =
new PrintStream(bos, false);
System.setOut(ps);
final int N = 100000;
for (int i = 1; i <= N; i++)
System.out.println(i);
ps.close();
}
}
这个程序输出1到100000到终端他比默认情况下快三倍。【随机读写文本文件】 import java.io.*; public class line1 {
public static void main(String args[]) {
if (args.length != 1) {
System.err.println("missing filename");
System.exit(1);
}
try {
FileInputStream fis =
new FileInputStream(args[0]);
BufferedInputStream bis =
new BufferedInputStream(fis);
DataInputStream dis =
new DataInputStream(bis);
int cnt = 0;
while (dis.readLine() != null)
cnt++;
dis.close();
System.out.println(cnt);
}
catch (IOException e) {
System.err.println(e);
}
}
}这个程序用了古老的DataInputStream.readLine来读取字符。
新一点的方法会象下面这样 import java.io.*; public class line2 {
public static void main(String args[]) {
if (args.length != 1) {
System.err.println("missing filename");
System.exit(1);
}
try {
FileReader fr = new FileReader(args[0]);
BufferedReader br = new BufferedReader(fr);
int cnt = 0;
while (br.readLine() != null)
cnt++;
br.close();
System.out.println(cnt);
}
catch (IOException e) {
System.err.println(e);
}
}
}
这个方法会快一些。比如6m 200,000行的文件读取第二种方式可以有20%的提升。
但即使没有提升也应该注意到一点。第一个方法会有警告,因为DataInputStream.readLine
这个方法没有正确变换字符,所以不要用它来处理文本文件。它可以处理ASCII的字节流。来看下面这段程序
import java.io.*;
public class conv1 {
public static void main(String args[]) {
try {
FileOutputStream fos =
new FileOutputStream("out1");
PrintStream ps =
new PrintStream(fos);
ps.println("\uffff\u4321\u1234");
ps.close();
}
catch (IOException e) {
System.err.println(e);
}
}
}显然他没有写我们能看懂的字符。☆Reader/Writer IO类是基于字符的,它可以来解决这类问题。
OutputStreamWriter 是设置编码的地方。
import java.io.*; public class conv2 {
public static void main(String args[]) {
try {
FileOutputStream fos =
new FileOutputStream("out2");
OutputStreamWriter osw =
new OutputStreamWriter(fos, "UTF8");
PrintWriter pw =
new PrintWriter(osw);
pw.println("\uffff\u4321\u1234");
pw.close();
}
catch (IOException e) {
System.err.println(e);
}
}
}
这段程序设置编码方式为UTF8。
看下面的三部分的例子。第一步 输出固定字符 public class format1 {
public static void main(String args[]) {
final int COUNT = 25000; for (int i = 1; i <= COUNT; i++) {
String s = "The square of 5 is 25\n";
System.out.print(s);
}
}
}
第二步 用+简单格式化 public class format2 {
public static void main(String args[]) {
int n = 5;
final int COUNT = 25000;
for (int i = 1; i <= COUNT; i++) {
String s = "The square of " + n + " is " +
n * n + "\n";
System.out.print(s);
}
}
}
第三步 用MessageFormat 格式化 import java.text.*;
public class format3 {
public static void main(String args[]) {
MessageFormat fmt =
new MessageFormat("The square of {0} is {1}\n");
Object values[] = new Object[2]; int n = 5; values[0] = new Integer(n);
values[1] = new Integer(n * n);
final int COUNT = 25000; for (int i = 1; i <= COUNT; i++) {
String s = fmt.format(values);
System.out.print(s);
}
}
}
下面是输出所需的时间
format1 1.3
format2 1.8
format3 7.8第四步 MessageFormat.format(String, Object[]) import java.text.*;
public class format4 {
public static void main(String args[]) {
String fmt = "The square of {0} is {1}\n";
Object values[] = new Object[2];
int n = 5;
values[0] = new Integer(n);
values[1] = new Integer(n * n);
final int COUNT = 25000;
for (int i = 1; i <= COUNT; i++) {
String s =
MessageFormat.format(fmt, values);
System.out.print(s);
}
}
}
这个代码用了上面代码的1/3的时间。
虽然第三步费时较长但是并不代表我们不用它。
实际上在国际化时是非常重要的。
RandomAccessFile 类用于对文件的随机访问。
他提供了seek方法类似c/c++中的found。
由于seek方法访问底层系统所以会比较费时。
一个比较可行的方法是在RandomAccessFile之上
构建自己的缓存来读取字节。例如
import java.io.*;
public class ReadRandom {
private static final int DEFAULT_BUFSIZE = 4096;
private RandomAccessFile raf;
private byte inbuf[];
private long startpos = -1;
private long endpos = -1;
private int bufsize;
public ReadRandom(String name)
throws FileNotFoundException {
this(name, DEFAULT_BUFSIZE);
}
public ReadRandom(String name, int b)
throws FileNotFoundException {
raf = new RandomAccessFile(name, "r");
bufsize = b;
inbuf = new byte[bufsize];
}
public int read(long pos) {
if (pos < startpos || pos > endpos) {
long blockstart = (pos / bufsize) * bufsize;
int n;
try {
raf.seek(blockstart);
n = raf.read(inbuf);
}
catch (IOException e) {
return -1;
}
startpos = blockstart;
endpos = blockstart + n - 1;
if (pos < startpos || pos > endpos)
return -1;
}
return inbuf[(int)(pos - startpos)] & 0xffff;
}
public void close() throws IOException {
raf.close();
}
public static void main(String args[]) {
if (args.length != 1) {
System.err.println("missing filename");
System.exit(1);
}
try {
ReadRandom rr = new ReadRandom(args[0]);
long pos = 0;
int c;
byte buf[] = new byte[1];
while ((c = rr.read(pos)) != -1) {
pos++;
buf[0] = (byte)c;
System.out.write(buf, 0, 1);
}
rr.close();
}
catch (IOException e) {
System.err.println(e);
}
}
}这个策略会在你想要得到你的访问点附近的数据的时候有用。【比较】
java 提供了类用于比较压缩的还没压缩的比特流。(java.util.zip package)
下面的代码接受一个文件输入,然后写到一个压缩文件里。import java.io.*;
import java.util.zip.*;
public class compress {
public static void doit(
String filein,
String fileout
) {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream(filein);
fos = new FileOutputStream(fileout);
ZipOutputStream zos =
new ZipOutputStream(fos);
ZipEntry ze = new ZipEntry(filein);
zos.putNextEntry(ze);
final int BUFSIZ = 4096;
byte inbuf[] = new byte[BUFSIZ];
int n;
while ((n = fis.read(inbuf)) != -1)
zos.write(inbuf, 0, n);
fis.close();
fis = null;
zos.close();
fos = null;
}
catch (IOException e) {
System.err.println(e);
}
finally {
try {
if (fis != null)
fis.close();
if (fos != null)
fos.close();
}
catch (IOException e) {
}
}
}
public static void main(String args[]) {
if (args.length != 2) {
System.err.println("missing filenames");
System.exit(1);
}
if (args[0].equals(args[1])) {
System.err.println("filenames are identical");
System.exit(1);
}
doit(args[0], args[1]);
}
}下面的程序用于解压
import java.io.*;
import java.util.zip.*;
public class uncompress {
public static void doit(
String filein,
String fileout
) {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream(filein);
fos = new FileOutputStream(fileout);
ZipInputStream zis = new ZipInputStream(fis);
ZipEntry ze = zis.getNextEntry();
final int BUFSIZ = 4096;
byte inbuf[] = new byte[BUFSIZ];
int n;
while ((n = zis.read(inbuf, 0, BUFSIZ)) != -1)
fos.write(inbuf, 0, n);
zis.close();
fis = null;
fos.close();
fos = null;
}
catch (IOException e) {
System.err.println(e);
}
finally {
try {
if (fis != null)
fis.close();
if (fos != null)
fos.close();
}
catch (IOException e) {
}
}
}
public static void main(String args[]) {
if (args.length != 2) {
System.err.println("missing filenames");
System.exit(1);
}
if (args[0].equals(args[1])) {
System.err.println("filenames are identical");
System.exit(1);
}
doit(args[0], args[1]);
}
}压缩是否有助于提升io性能很大程度上拒绝与你的硬件设置,特别是cpu和硬盘。
zip压缩技术可以减少50%的数据量,但需要时间压缩和解压缩。
压缩常见的应用是往低速设备上(软盘)写入。它可以节约50%的时间。
【缓存】
详细的硬件缓存讨论超出了本文范围。但是有时软件的缓存可以提升io.
考虑这样一个情况。你想以随机方式读入一个文本文件。
一个方法是读所有的行存入arraylist. import java.io.*;
import java.util.ArrayList;
public class LineCache {
private ArrayList list = new ArrayList();
public LineCache(String fn) throws IOException {
FileReader fr = new FileReader(fn);
BufferedReader br = new BufferedReader(fr);
String ln;
while ((ln = br.readLine()) != null)
list.add(ln);
br.close();
}
public String getLine(int n) {
if (n < 0)
throw new IllegalArgumentException();
return (n < list.size() ?
(String)list.get(n) : null);
}
public static void main(String args[]) {
if (args.length != 1) {
System.err.println("missing filename");
System.exit(1);
}
try {
LineCache lc = new LineCache(args[0]);
int i = 0;
String ln;
while ((ln = lc.getLine(i++)) != null)
System.out.println(ln);
}
catch (IOException e) {
System.err.println(e);
}
}
}
getLine 方法用于提取行.这很常用但耗费大量内存.
一个改进的方法是记住最近被请求的100行.Tokenization(不会翻译)
Tokenization把字节或者字符序列分成逻辑快 比如词. import java.io.*;
public class token1 {
public static void main(String args[]) {
if (args.length != 1) {
System.err.println("missing filename");
System.exit(1);
}
try {
FileReader fr = new FileReader(args[0]);
BufferedReader br = new BufferedReader(fr);
StreamTokenizer st = new StreamTokenizer(br);
st.resetSyntax();
st.wordChars('a', 'z');
int tok;
while ((tok = st.nextToken()) !=
StreamTokenizer.TT_EOF) {
if (tok == StreamTokenizer.TT_WORD)
;// st.sval has token
}
br.close();
}
catch (IOException e) {
System.err.println(e);
}
}
}
同样的功能
import java.io.*;
public class token2 {
public static void main(String args[]) {
if (args.length != 1) {
System.err.println("missing filename");
System.exit(1);
}
try {
FileReader fr = new FileReader(args[0]);
BufferedReader br = new BufferedReader(fr);
int maxlen = 256;
int currlen = 0;
char wordbuf[] = new char[maxlen];
int c;
do {
c = br.read();
if (c >= 'a' && c <= 'z') {
if (currlen == maxlen) {
maxlen *= 1.5;
char xbuf[] =
new char[maxlen];
System.arraycopy(
wordbuf, 0,
xbuf, 0, currlen);
wordbuf = xbuf;
}
wordbuf[currlen++] = (char)c;
}
else if (currlen > 0) {
String s = new String(wordbuf,
0, currlen);
// do something with s
currlen = 0;
}
} while (c != -1);
br.close();
}
catch (IOException e) {
System.err.println(e);
}
}
}
第二个比第一个快20%.
下边的例子输出一串随机数
import java.io.*;
import java.util.*;
public class serial1 {
public static void main(String args[]) {
ArrayList al = new ArrayList();
Random rn = new Random();
final int N = 100000;
for (int i = 1; i <= N; i++)
al.add(new Integer(rn.nextInt()));
try {
FileOutputStream fos =
new FileOutputStream("test.ser");
BufferedOutputStream bos =
new BufferedOutputStream(fos);
ObjectOutputStream oos =
new ObjectOutputStream(bos);
oos.writeObject(al);
oos.close();
}
catch (Throwable e) {
System.err.println(e);
}
}
}
读入arraylist
import java.io.*;
import java.util.*;
public class serial2 {
public static void main(String args[]) {
ArrayList al = null;
try {
FileInputStream fis =
new FileInputStream("test.ser");
BufferedInputStream bis =
new BufferedInputStream(fis);
ObjectInputStream ois =
new ObjectInputStream(bis);
al = (ArrayList)ois.readObject();
ois.close();
}
catch (Throwable e) {
System.err.println(e);
}
}
}
这里我们都用了缓存.
是不是有更快的方法来序列化输出大量数据呢.很可能没有.
比如.你决定写64比特的长整数而不是8个比特.长整数的最大长度
大约是20个字符.是二进制表示长度的2.5倍.所以这种格式不会再快了.
但在特殊情况下,比如bitmaps可能情况会不一样。除了实际的io ,序列化的格式化开销(在DataInputStream和DataOutputStream中),
还有其他的开销,比如反序列化。比如
import java.io.*;
import java.util.*;
public class binary1 {
public static void main(String args[]) {
try {
FileOutputStream fos =
new FileOutputStream("outdata");
BufferedOutputStream bos =
new BufferedOutputStream(fos);
DataOutputStream dos =
new DataOutputStream(bos);
Random rn = new Random();
final int N = 10;
dos.writeInt(N);
for (int i = 1; i <= N; i++) {
int r = rn.nextInt();
System.out.println(r);
dos.writeInt(r);
}
dos.close();
}
catch (IOException e) {
System.err.println(e);
}
}
}
和
import java.io.*;
public class binary2 {
public static void main(String args[]) {
try {
FileInputStream fis =
new FileInputStream("outdata");
BufferedInputStream bis =
new BufferedInputStream(fis);
DataInputStream dis =
new DataInputStream(bis);
int N = dis.readInt();
for (int i = 1; i <= N; i++) {
int r = dis.readInt();
System.out.println(r);
}
dis.close();
}
catch (IOException e) {
System.err.println(e);
}
}
}【获取文件信息】
到现在为止我们提到的都是IO.但还有一个方面值得我们注意,那就是关于获取文件信息的操作。
import java.io.*;
public class length1 {
public static void main(String args[]) {
if (args.length != 1) {
System.err.println("missing filename");
System.exit(1);
}
File f = new File(args[0]);
long len = f.length();
System.out.println(len);
}
}
JAVA 虚拟机自己并不知道文件的长度所以必须去调用系统函数。
对于文件的其他属性也一样,比如文件的更新时间等。另外一个例子 import java.io.*;
public class roots {
public static void visit(File f) {
System.out.println(f);
}
public static void walk(File f) {
visit(f);
if (f.isDirectory()) {
String list[] = f.list();
for (int i = 0; i < list.length; i++)
walk(new File(f, list[i]));
}
}
public static void main(String args[]) {
File list[] = File.listRoots();
for (int i = 0; i < list.length; i++) {
if (list[i].exists())
walk(list[i]);
else
System.err.println("not accessible: "
+ list[i]);
}
}
}
他用了File 的方法比如isDirectory 和 exists。
每个文件仅仅访问一次。