首页 文章资讯内容详情

java IO 理解

2026-06-01 4 花语

本文内容纲要:

-字节流 -字符流 -关于字节流和字符流的区别 -使用字节流好还是字符流好呢?

写在前面:本文章基本覆盖了javaIO的全部内容,java新IO没有涉及,因为我想和这个分开,以突出那个的重要性,新IO哪一篇文章还没有开始写,估计很快就能和大家见面。照旧,文章依旧以例子为主,因为讲解内容的java书很多了,我觉的学以致用才是真。代码是写出来的,不是看出来的。

最后欢迎大家提出意见和建议。

【案例1】创建一个新文件

importjava.io.*; classhello{ publicstaticvoidmain(String[]args){ Filef=newFile("D:\\hello.txt"); try{ f.createNewFile(); }catch(Exceptione){ e.printStackTrace(); } } }

【运行结果】:

程序运行之后,在d盘下会有一个名字为hello.txt的文件。

【案例2】File类的两个常量

importjava.io.*; classhello{ publicstaticvoidmain(String[]args){ System.out.println(File.separator); System.out.println(File.pathSeparator); } }

【运行结果】:

\

;

此处多说几句:有些同学可能认为,我直接在windows下使用\进行分割不行吗?当然是可以的。但是在linux下就不是\了。所以,要想使得我们的代码跨平台,更加健壮,所以,大家都采用这两个常量吧,其实也多写不了几行。呵呵、

现在我们使用File类中的常量改写上面的代码:

importjava.io.*; classhello{ publicstaticvoidmain(String[]args){ StringfileName="D:"+File.separator+"hello.txt"; Filef=newFile(fileName); try{ f.createNewFile(); }catch(Exceptione){ e.printStackTrace(); } } }

你看,没有多写多少吧,呵呵。所以建议使用File类中的常量。

删除一个文件

/** *删除一个文件 **/ importjava.io.*; classhello{ publicstaticvoidmain(String[]args){ StringfileName="D:"+File.separator+"hello.txt"; Filef=newFile(fileName); if(f.exists()){ f.delete(); }else{ System.out.println("文件不存在"); } } }

创建一个文件夹

/** *创建一个文件夹 **/ importjava.io.*; classhello{ publicstaticvoidmain(String[]args){ StringfileName="D:"+File.separator+"hello"; Filef=newFile(fileName); f.mkdir(); } }

【运行结果】:

D盘下多了一个hello文件夹

列出指定目录的全部文件(包括隐藏文件):

/** *使用list列出指定目录的全部文件 **/ importjava.io.*; classhello{ publicstaticvoidmain(String[]args){ StringfileName="D:"+File.separator; Filef=newFile(fileName); String[]str=f.list(); for(inti=0;i<str.length;i++){ System.out.println(str[i]); } } }

【运行结果】:

$RECYCLE.BIN

360

360Downloads

360Rec

360SoftMove

Config.Msi

da

Downloads

DriversBackup

eclipse

javaweb整合开发和项目实战

Lenovo

MSOCache

Program

ProgramFiles

python

RECYGLER.{8F92DA15-A229-A4D5-B5CE-5280C8B89C19}

SystemVolumeInformation

Tomcat6

var

vod_cache_data

新建文件夹

(你的运行结果应该和这个不一样的,呵呵)

但是使用list返回的是String数组,。而且列出的不是完整路径,如果想列出完整路径的话,需要使用listFiles.他返回的是File的数组

列出指定目录的全部文件(包括隐藏文件):

/** *使用listFiles列出指定目录的全部文件 *listFiles输出的是完整路径 **/ importjava.io.*; classhello{ publicstaticvoidmain(String[]args){ StringfileName="D:"+File.separator; Filef=newFile(fileName); File[]str=f.listFiles(); for(inti=0;i<str.length;i++){ System.out.println(str[i]); } } }

【运行结果】:

D:\$RECYCLE.BIN

D:\360

D:\360Downloads

D:\360Rec

D:\360SoftMove

D:\Config.Msi

D:\da

D:\Downloads

D:\DriversBackup

D:\eclipse

D:\javaweb整合开发和项目实战

D:\Lenovo

D:\MSOCache

D:\Program

D:\ProgramFiles

D:\python

D:\RECYGLER.{8F92DA15-A229-A4D5-B5CE-5280C8B89C19}

D:\SystemVolumeInformation

D:\Tomcat6

D:\var

D:\vod_cache_data

D:\新建文件夹

通过比较可以指定,使用listFiles更加方便、

判断一个指定的路径是否为目录

/** *使用isDirectory判断一个指定的路径是否为目录 **/ importjava.io.*; classhello{ publicstaticvoidmain(String[]args){ StringfileName="D:"+File.separator; Filef=newFile(fileName); if(f.isDirectory()){ System.out.println("YES"); }else{ System.out.println("NO"); } } }

【运行结果】:YES

搜索指定目录的全部内容

/** *列出指定目录的全部内容 **/ importjava.io.*; classhello{ publicstaticvoidmain(String[]args){ StringfileName="D:"+File.separator; Filef=newFile(fileName); print(f); } publicstaticvoidprint(Filef){ if(f!=null){ if(f.isDirectory()){ File[]fileArray=f.listFiles(); if(fileArray!=null){ for(inti=0;i<fileArray.length;i++){ //递归调用 print(fileArray[i]); } } } else{ System.out.println(f); } } } }

【运行结果】:

D:\Tomcat6\work\Catalina\localhost\nevel\org\apache\jsp\framepages\web4welcome_jsp.java

D:\Tomcat6\work\Catalina\localhost\nevel\org\apache\jsp\help_005fhome_jsp.class

D:\Tomcat6\work\Catalina\localhost\nevel\org\apache\jsp\help_005fhome_jsp.java

D:\Tomcat6\work\Catalina\localhost\nevel\org\apache\jsp\home_jsp.class

D:\Tomcat6\work\Catalina\localhost\nevel\org\apache\jsp\home_jsp.java

D:\Tomcat6\work\Catalina\localhost\nevel\org\apache\jsp\index_jsp.class

D:\Tomcat6\work\Catalina\localhost\nevel\org\apache\jsp\index_jsp.java

D:\Tomcat6\work\Catalina\localhost\nevel\org\apache\jsp\login_jsp.class

D:\Tomcat6\work\Catalina\localhost\nevel\org\apache\jsp\login_jsp.java

D:\Tomcat6\work\Catalina\localhost\nevel\org\apache\jsp\modify_005fuser_005finfo_jsp.class

D:\Tomcat6\work\Catalina\localhost\nevel\org\apache\jsp\modify_005fuser_005finfo_jsp.java

D:\Tomcat6\work\Catalina\localhost\nevel\org\apache\jsp\register_005fnotify_jsp.class

D:\Tomcat6\work\Catalina\localhost\nevel\org\apache\jsp\register_005fnotify_jsp.java

D:\Tomcat6\work\Catalina\localhost\nevel\org\apache\jsp\sign_005fup_jsp.class

D:\Tomcat6\work\Catalina\localhost\nevel\org\apache\jsp\sign_005fup_jsp.java

D:\Tomcat6\work\Catalina\localhost\nevel\org\apache\jsp\transit_jsp.class

……

使用RandomAccessFile写入文件

/** *使用RandomAccessFile写入文件 **/ importjava.io.*; classhello{ publicstaticvoidmain(String[]args)throwsIOException{ StringfileName="D:"+File.separator+"hello.txt"; Filef=newFile(fileName); RandomAccessFiledemo=newRandomAccessFile(f,"rw"); demo.writeBytes("asdsad"); demo.writeInt(12); demo.writeBoolean(true); demo.writeChar(A); demo.writeFloat(1.21f); demo.writeDouble(12.123); demo.close(); } }

如果你此时打开hello。txt查看的话,会发现那是乱码。

字节流

【向文件中写入字符串】

/** *字节流 *向文件中写入字符串 **/ importjava.io.*; classhello{ publicstaticvoidmain(String[]args)throwsIOException{ StringfileName="D:"+File.separator+"hello.txt"; Filef=newFile(fileName); OutputStreamout=newFileOutputStream(f); Stringstr="你好"; byte[]b=str.getBytes(); out.write(b); out.close(); } }

查看hello.txt会看到“你好”

当然也可以一个字节一个字节的写。

/** *字节流 *向文件中一个字节一个字节的写入字符串 **/ importjava.io.*; classhello{ publicstaticvoidmain(String[]args)throwsIOException{ StringfileName="D:"+File.separator+"hello.txt"; Filef=newFile(fileName); OutputStreamout=newFileOutputStream(f); Stringstr="你好"; byte[]b=str.getBytes(); for(inti=0;i<b.length;i++){ out.write(b[i]); } out.close(); } }

结果还是:“你好”

向文件中追加新内容:

/** *字节流 *向文件中追加新内容: **/ importjava.io.*; classhello{ publicstaticvoidmain(String[]args)throwsIOException{ StringfileName="D:"+File.separator+"hello.txt"; Filef=newFile(fileName); OutputStreamout=newFileOutputStream(f,true); Stringstr="Rollen"; //Stringstr="\r\nRollen";可以换行 byte[]b=str.getBytes(); for(inti=0;i<b.length;i++){ out.write(b[i]); } out.close(); } }

【运行结果】:

你好Rollen

【读取文件内容】

/** *字节流 *读文件内容 **/ importjava.io.*; classhello{ publicstaticvoidmain(String[]args)throwsIOException{ StringfileName="D:"+File.separator+"hello.txt"; Filef=newFile(fileName); InputStreamin=newFileInputStream(f); byte[]b=newbyte[1024]; in.read(b); in.close(); System.out.println(newString(b)); } }

【运行结果】

你好Rollen

Rollen_

但是这个例子读取出来会有大量的空格,我们可以利用in.read(b);的返回值来设计程序。如下:

/** *字节流 *读文件内容 **/ importjava.io.*; classhello{ publicstaticvoidmain(String[]args)throwsIOException{ StringfileName="D:"+File.separator+"hello.txt"; Filef=newFile(fileName); InputStreamin=newFileInputStream(f); byte[]b=newbyte[1024]; intlen=in.read(b); in.close(); System.out.println("读入长度为:"+len); System.out.println(newString(b,0,len)); } }

【运行结果】:

读入长度为:18

你好Rollen

Rollen

读者观察上面的例子可以看出,我们预先申请了一个指定大小的空间,但是有时候这个空间可能太小,有时候可能太大,我们需要准确的大小,这样节省空间,那么我们可以这样干:

/** *字节流 *读文件内容,节省空间 **/ importjava.io.*; classhello{ publicstaticvoidmain(String[]args)throwsIOException{ StringfileName="D:"+File.separator+"hello.txt"; Filef=newFile(fileName); InputStreamin=newFileInputStream(f); byte[]b=newbyte[(int)f.length()]; in.read(b); System.out.println("文件长度为:"+f.length()); in.close(); System.out.println(newString(b)); } }

文件长度为:18

你好Rollen

Rollen

将上面的例子改为一个一个读:

/** *字节流 *读文件内容,节省空间 **/ importjava.io.*; classhello{ publicstaticvoidmain(String[]args)throwsIOException{ StringfileName="D:"+File.separator+"hello.txt"; Filef=newFile(fileName); InputStreamin=newFileInputStream(f); byte[]b=newbyte[(int)f.length()]; for(inti=0;i<b.length;i++){ b[i]=(byte)in.read(); } in.close(); System.out.println(newString(b)); } }

输出的结果和上面的一样。

细心的读者可能会发现,上面的几个例子都是在知道文件的内容多大,然后才展开的,有时候我们不知道文件有多大,这种情况下,我们需要判断是否独到文件的末尾。

/** *字节流 *读文件 **/ importjava.io.*; classhello{ publicstaticvoidmain(String[]args)throwsIOException{ StringfileName="D:"+File.separator+"hello.txt"; Filef=newFile(fileName); InputStreamin=newFileInputStream(f); byte[]b=newbyte[1024]; intcount=0; inttemp=0; while((temp=in.read())!=(-1)){ b[count++]=(byte)temp; } in.close(); System.out.println(newString(b)); } }

【运行结果】

你好Rollen

Rollen_

提醒一下,当独到文件末尾的时候会返回-1.正常情况下是不会返回-1的

字符流

【向文件中写入数据】

现在我们使用字符流

/** *字符流 *写入数据 **/ importjava.io.*; classhello{ publicstaticvoidmain(String[]args)throwsIOException{ StringfileName="D:"+File.separator+"hello.txt"; Filef=newFile(fileName); Writerout=newFileWriter(f); Stringstr="hello"; out.write(str); out.close(); } }

当你打开hello。txt的时候,会看到hello

其实这个例子上之前的例子没什么区别,只是你可以直接输入字符串,而不需要你将字符串转化为字节数组。

当你如果想问文件中追加内容的时候,可以使用将上面的声明out的哪一行换为:

Writerout=newFileWriter(f,true);

这样,当你运行程序的时候,会发现文件内容变为:

hellohello如果想在文件中换行的话,需要使用“\r\n”

比如将str变为Stringstr="\r\nhello";

这样文件追加的str的内容就会换行了。

从文件中读内容:

/** *字符流 *从文件中读出内容 **/ importjava.io.*; classhello{ publicstaticvoidmain(String[]args)throwsIOException{ StringfileName="D:"+File.separator+"hello.txt"; Filef=newFile(fileName); char[]ch=newchar[100]; Readerread=newFileReader(f); intcount=read.read(ch); read.close(); System.out.println("读入的长度为:"+count); System.out.println("内容为"+newString(ch,0,count)); } }

【运行结果】:

读入的长度为:17

内容为hellohello

hello

当然最好采用循环读取的方式,因为我们有时候不知道文件到底有多大。

/** *字符流 *从文件中读出内容 **/ importjava.io.*; classhello{ publicstaticvoidmain(String[]args)throwsIOException{ StringfileName="D:"+File.separator+"hello.txt"; Filef=newFile(fileName); char[]ch=newchar[100]; Readerread=newFileReader(f); inttemp=0; intcount=0; while((temp=read.read())!=(-1)){ ch[count++]=(char)temp; } read.close(); System.out.println("内容为"+newString(ch,0,count)); } }

运行结果:

内容为hellohello

hello

关于字节流和字符流的区别

实际上字节流在操作的时候本身是不会用到缓冲区的,是文件本身的直接操作的,但是字符流在操作的时候下后是会用到缓冲区的,是通过缓冲区来操作文件的。

读者可以试着将上面的字节流和字符流的程序的最后一行关闭文件的代码注释掉,然后运行程序看看。你就会发现使用字节流的话,文件中已经存在内容,但是使用字符流的时候,文件中还是没有内容的,这个时候就要刷新缓冲区。

使用字节流好还是字符流好呢?

答案是字节流。首先因为硬盘上的所有文件都是以字节的形式进行传输或者保存的,包括图片等内容。但是字符只是在内存中才会形成的,所以在开发中,字节流使用广泛。

文件的复制

其实DOS下就有一个文件复制功能,比如我们想把d盘下面的hello.txt文件复制到d盘下面的rollen.txt文件中,那么我们就可以使用下面的命令:

copyd:\hello.txtd:\rollen.txt

运行之后你会在d盘中看见hello.txt.,并且两个文件的内容是一样的,(这是屁话)

下面我们使用程序来复制文件吧。

基本思路还是从一个文件中读入内容,边读边写入另一个文件,就是这么简单。、

首先编写下面的代码:

/** *文件的复制 **/ importjava.io.*; classhello{ publicstaticvoidmain(String[]args)throwsIOException{ if(args.length!=2){ System.out.println("命令行参数输入有误,请检查"); System.exit(1); } Filefile1=newFile(args[0]); Filefile2=newFile(args[1]); if(!file1.exists()){ System.out.println("被复制的文件不存在"); System.exit(1); } InputStreaminput=newFileInputStream(file1); OutputStreamoutput=newFileOutputStream(file2); if((input!=null)&&(output!=null)){ inttemp=0; while((temp=input.read())!=(-1)){ output.write(temp); } } input.close(); output.close(); } }

然后在命令行下面

javachello.java

javahellod:\hello.txtd:\rollen.txt

现在你就会在d盘看到rollen。txt了,

OutputStreramWriter和InputStreamReader类

整个IO类中除了字节流和字符流还包括字节和字符转换流。

OutputStreramWriter将输出的字符流转化为字节流

InputStreamReader将输入的字节流转换为字符流

但是不管如何操作,最后都是以字节的形式保存在文件中的。

将字节输出流转化为字符输出流 /** *将字节输出流转化为字符输出流 **/ importjava.io.*; classhello{ publicstaticvoidmain(String[]args)throwsIOException{ StringfileName="d:"+File.separator+"hello.txt"; Filefile=newFile(fileName); Writerout=newOutputStreamWriter(newFileOutputStream(file)); out.write("hello"); out.close(); } }

运行结果:文件中内容为:hello

将字节输入流变为字符输入流 /** *将字节输入流变为字符输入流 **/ importjava.io.*; classhello{ publicstaticvoidmain(String[]args)throwsIOException{ StringfileName="d:"+File.separator+"hello.txt"; Filefile=newFile(fileName); Readerread=newInputStreamReader(newFileInputStream(file)); char[]b=newchar[100]; intlen=read.read(b); System.out.println(newString(b,0,len)); read.close(); } }

【运行结果】:hello

前面列举的输出输入都是以文件进行的,现在我们以内容为输出输入目的地,使用内存操作流

ByteArrayInputStream主要将内容写入内容

ByteArrayOutputStream主要将内容从内存输出

使用内存操作流将一个大写字母转化为小写字母 /** *使用内存操作流将一个大写字母转化为小写字母 **/ importjava.io.*; classhello{ publicstaticvoidmain(String[]args)throwsIOException{ Stringstr="ROLLENHOLT"; ByteArrayInputStreaminput=newByteArrayInputStream(str.getBytes()); ByteArrayOutputStreamoutput=newByteArrayOutputStream(); inttemp=0; while((temp=input.read())!=-1){ charch=(char)temp; output.write(Character.toLowerCase(ch)); } StringoutStr=output.toString(); input.close(); output.close(); System.out.println(outStr); } }

【运行结果】:

rollenholt

内容操作流一般使用来生成一些临时信息采用的,这样可以避免删除的麻烦。

管道流

管道流主要可以进行两个线程之间的通信。

PipedOutputStream管道输出流

PipedInputStream管道输入流

验证管道流 /** *验证管道流 **/ importjava.io.*; /** *消息发送类 **/ classSendimplementsRunnable{ privatePipedOutputStreamout=null; publicSend(){ out=newPipedOutputStream(); } publicPipedOutputStreamgetOut(){ returnthis.out; } publicvoidrun(){ Stringmessage="hello,Rollen"; try{ out.write(message.getBytes()); }catch(Exceptione){ e.printStackTrace(); }try{ out.close(); }catch(Exceptione){ e.printStackTrace(); } } } /** *接受消息类 **/ classReciveimplementsRunnable{ privatePipedInputStreaminput=null; publicRecive(){ this.input=newPipedInputStream(); } publicPipedInputStreamgetInput(){ returnthis.input; } publicvoidrun(){ byte[]b=newbyte[1000]; intlen=0; try{ len=this.input.read(b); }catch(Exceptione){ e.printStackTrace(); }try{ input.close(); }catch(Exceptione){ e.printStackTrace(); } System.out.println("接受的内容为"+(newString(b,0,len))); } } /** *测试类 **/ classhello{ publicstaticvoidmain(String[]args)throwsIOException{ Sendsend=newSend(); Reciverecive=newRecive(); try{ //管道连接 send.getOut().connect(recive.getInput()); }catch(Exceptione){ e.printStackTrace(); } newThread(send).start(); newThread(recive).start(); } }

【运行结果】:

接受的内容为hello,Rollen

打印流 /** *使用PrintStream进行输出 **/ importjava.io.*; classhello{ publicstaticvoidmain(String[]args)throwsIOException{ PrintStreamprint=newPrintStream(newFileOutputStream(newFile("d:" +File.separator+"hello.txt"))); print.println(true); print.println("Rollen"); print.close(); } }

【运行结果】:

true

Rollen

当然也可以格式化输出

/** *使用PrintStream进行输出 *并进行格式化 **/ importjava.io.*; classhello{ publicstaticvoidmain(String[]args)throwsIOException{ PrintStreamprint=newPrintStream(newFileOutputStream(newFile("d:" +File.separator+"hello.txt"))); Stringname="Rollen"; intage=20; print.printf("姓名:%s.年龄:%d.",name,age); print.close(); } }

【运行结果】:

姓名:Rollen.年龄:20.

使用OutputStream向屏幕上输出内容

/** *使用OutputStream向屏幕上输出内容 **/ importjava.io.*; classhello{ publicstaticvoidmain(String[]args)throwsIOException{ OutputStreamout=System.out; try{ out.write("hello".getBytes()); }catch(Exceptione){ e.printStackTrace(); } try{ out.close(); }catch(Exceptione){ e.printStackTrace(); } } }

【运行结果】:

hello

输入输出重定向 importjava.io.File; importjava.io.FileNotFoundException; importjava.io.FileOutputStream; importjava.io.PrintStream; /** *为System.out.println()重定向输出 **/ publicclasssystemDemo{ publicstaticvoidmain(String[]args){ //此刻直接输出到屏幕 System.out.println("hello"); Filefile=newFile("d:"+File.separator+"hello.txt"); try{ System.setOut(newPrintStream(newFileOutputStream(file))); }catch(FileNotFoundExceptione){ e.printStackTrace(); } System.out.println("这些内容在文件中才能看到哦!"); } }

【运行结果】:

eclipse的控制台输出的是hello。然后当我们查看d盘下面的hello.txt文件的时候,会在里面看到:这些内容在文件中才能看到哦!

importjava.io.File; importjava.io.FileNotFoundException; importjava.io.FileOutputStream; importjava.io.PrintStream; /** *System.err重定向这个例子也提示我们可以使用这种方法保存错误信息 **/ publicclasssystemErr{ publicstaticvoidmain(String[]args){ Filefile=newFile("d:"+File.separator+"hello.txt"); System.err.println("这些在控制台输出"); try{ System.setErr(newPrintStream(newFileOutputStream(file))); }catch(FileNotFoundExceptione){ e.printStackTrace(); } System.err.println("这些在文件中才能看到哦!"); } }

【运行结果】:

你会在eclipse的控制台看到红色的输出:“这些在控制台输出”,然后在d盘下面的hello.txt中会看到:这些在文件中才能看到哦!

importjava.io.File; importjava.io.FileInputStream; importjava.io.FileNotFoundException; importjava.io.IOException; /** *System.in重定向 **/ publicclasssystemIn{ publicstaticvoidmain(String[]args){ Filefile=newFile("d:"+File.separator+"hello.txt"); if(!file.exists()){ return; }else{ try{ System.setIn(newFileInputStream(file)); }catch(FileNotFoundExceptione){ e.printStackTrace(); } byte[]bytes=newbyte[1024]; intlen=0; try{ len=System.in.read(bytes); }catch(IOExceptione){ e.printStackTrace(); } System.out.println("读入的内容为:"+newString(bytes,0,len)); } } }

【运行结果】:

前提是我的d盘下面的hello.txt中的内容是:“这些文件中的内容哦!”,然后运行程序,输出的结果为:读入的内容为:这些文件中的内容哦!

BufferedReader的小例子

注意:BufferedReader只能接受字符流的缓冲区,因为每一个中文需要占据两个字节,所以需要将System.in这个字节输入流变为字符输入流,采用:

BufferedReaderbuf=newBufferedReader( newInputStreamReader(System.in));

下面给一个实例:

importjava.io.BufferedReader; importjava.io.IOException; importjava.io.InputStreamReader; /** *使用缓冲区从键盘上读入内容 **/ publicclassBufferedReaderDemo{ publicstaticvoidmain(String[]args){ BufferedReaderbuf=newBufferedReader( newInputStreamReader(System.in)); Stringstr=null; System.out.println("请输入内容"); try{ str=buf.readLine(); }catch(IOExceptione){ e.printStackTrace(); } System.out.println("你输入的内容是:"+str); } }

运行结果:

请输入内容

dasdas

你输入的内容是:dasdas

Scanner类

其实我们比较常用的是采用Scanner类来进行数据输入,下面来给一个Scanner的例子吧

importjava.util.Scanner; /** *Scanner的小例子,从键盘读数据 **/ publicclassScannerDemo{ publicstaticvoidmain(String[]args){ Scannersca=newScanner(System.in); //读一个整数 inttemp=sca.nextInt(); System.out.println(temp); //读取浮点数 floatflo=sca.nextFloat(); System.out.println(flo); //读取字符 //...等等的,都是一些太基础的,就不师范了。 } }

其实Scanner可以接受任何的输入流

下面给一个使用Scanner类从文件中读出内容

importjava.io.File; importjava.io.FileNotFoundException; importjava.util.Scanner; /** *Scanner的小例子,从文件中读内容 **/ publicclassScannerDemo{ publicstaticvoidmain(String[]args){ Filefile=newFile("d:"+File.separator+"hello.txt"); Scannersca=null; try{ sca=newScanner(file); }catch(FileNotFoundExceptione){ e.printStackTrace(); } Stringstr=sca.next(); System.out.println("从文件中读取的内容是:"+str); } }

【运行结果】:

从文件中读取的内容是:这些文件中的内容哦!

数据操作流DataOutputStream、DataInputStream类 importjava.io.DataOutputStream; importjava.io.File; importjava.io.FileOutputStream; importjava.io.IOException; publicclassDataOutputStreamDemo{ publicstaticvoidmain(String[]args)throwsIOException{ Filefile=newFile("d:"+File.separator+"hello.txt"); char[]ch={A,B,C}; DataOutputStreamout=null; out=newDataOutputStream(newFileOutputStream(file)); for(chartemp:ch){ out.writeChar(temp); } out.close(); } }

ABC

现在我们在上面例子的基础上,使用DataInputStream读出内容

importjava.io.DataInputStream; importjava.io.File; importjava.io.FileInputStream; importjava.io.IOException; publicclassDataOutputStreamDemo{ publicstaticvoidmain(String[]args)throwsIOException{ Filefile=newFile("d:"+File.separator+"hello.txt"); DataInputStreaminput=newDataInputStream(newFileInputStream(file)); char[]ch=newchar[10]; intcount=0; chartemp; while((temp=input.readChar())!=C){ ch[count++]=temp; } System.out.println(ch); } }

【运行结果】:

AB

合并流SequenceInputStream

SequenceInputStream主要用来将2个流合并在一起,比如将两个txt中的内容合并为另外一个txt。下面给出一个实例:

importjava.io.File; importjava.io.FileInputStream; importjava.io.FileOutputStream; importjava.io.IOException; importjava.io.InputStream; importjava.io.OutputStream; importjava.io.SequenceInputStream; /** *将两个文本文件合并为另外一个文本文件 **/ publicclassSequenceInputStreamDemo{ publicstaticvoidmain(String[]args)throwsIOException{ Filefile1=newFile("d:"+File.separator+"hello1.txt"); Filefile2=newFile("d:"+File.separator+"hello2.txt"); Filefile3=newFile("d:"+File.separator+"hello.txt"); InputStreaminput1=newFileInputStream(file1); InputStreaminput2=newFileInputStream(file2); OutputStreamoutput=newFileOutputStream(file3); //合并流 SequenceInputStreamsis=newSequenceInputStream(input1,input2); inttemp=0; while((temp=sis.read())!=-1){ output.write(temp); } input1.close(); input2.close(); output.close(); sis.close(); } }

【运行结果】

结果会在hello.txt文件中包含hello1.txt和hello2.txt文件中的内容。

文件压缩ZipOutputStream类

先举一个压缩单个文件的例子吧:

importjava.io.File; importjava.io.FileInputStream; importjava.io.FileOutputStream; importjava.io.IOException; importjava.io.InputStream; importjava.util.zip.ZipEntry; importjava.util.zip.ZipOutputStream; publicclassZipOutputStreamDemo1{ publicstaticvoidmain(String[]args)throwsIOException{ Filefile=newFile("d:"+File.separator+"hello.txt"); FilezipFile=newFile("d:"+File.separator+"hello.zip"); InputStreaminput=newFileInputStream(file); ZipOutputStreamzipOut=newZipOutputStream(newFileOutputStream( zipFile)); zipOut.putNextEntry(newZipEntry(file.getName())); //设置注释 zipOut.setComment("hello"); inttemp=0; while((temp=input.read())!=-1){ zipOut.write(temp); } input.close(); zipOut.close(); } }

【运行结果】

运行结果之前,我创建了一个hello.txt的文件,原本大小56个字节,但是压缩之后产生hello.zip之后,居然变成了175个字节,有点搞不懂。

不过结果肯定是正确的,我只是提出我的一个疑问而已。

上面的这个例子测试的是压缩单个文件,下面的们来看看如何压缩多个文件。

importjava.io.File; importjava.io.FileInputStream; importjava.io.FileOutputStream; importjava.io.IOException; importjava.io.InputStream; importjava.util.zip.ZipEntry; importjava.util.zip.ZipOutputStream; /** *一次性压缩多个文件 **/ publicclassZipOutputStreamDemo2{ publicstaticvoidmain(String[]args)throwsIOException{ //要被压缩的文件夹 Filefile=newFile("d:"+File.separator+"temp"); FilezipFile=newFile("d:"+File.separator+"zipFile.zip"); InputStreaminput=null; ZipOutputStreamzipOut=newZipOutputStream(newFileOutputStream( zipFile)); zipOut.setComment("hello"); if(file.isDirectory()){ File[]files=file.listFiles(); for(inti=0;i<files.length;++i){ input=newFileInputStream(files[i]); zipOut.putNextEntry(newZipEntry(file.getName() +File.separator+files[i].getName())); inttemp=0; while((temp=input.read())!=-1){ zipOut.write(temp); } input.close(); } } zipOut.close(); } }

【运行结果】

先看看要被压缩的文件吧:

接下来看看压缩之后的:

大家自然想到,既然能压缩,自然能解压缩,在谈解压缩之前,我们会用到一个ZipFile类,先给一个这个例子吧。java中的每一个压缩文件都是可以使用ZipFile来进行表示的

importjava.io.File; importjava.io.IOException; importjava.util.zip.ZipFile; /** *ZipFile演示 **/ publicclassZipFileDemo{ publicstaticvoidmain(String[]args)throwsIOException{ Filefile=newFile("d:"+File.separator+"hello.zip"); ZipFilezipFile=newZipFile(file); System.out.println("压缩文件的名称为:"+zipFile.getName()); } }

【运行结果】:

压缩文件的名称为:d:\hello.zip

现在我们呢是时候来看看如何加压缩文件了,和之前一样,先让我们来解压单个压缩文件(也就是压缩文件中只有一个文件的情况),我们采用前面的例子产生的压缩文件hello.zip

importjava.io.File; importjava.io.FileOutputStream; importjava.io.IOException; importjava.io.InputStream; importjava.io.OutputStream; importjava.util.zip.ZipEntry; importjava.util.zip.ZipFile; /** *解压缩文件(压缩文件中只有一个文件的情况) **/ publicclassZipFileDemo2{ publicstaticvoidmain(String[]args)throwsIOException{ Filefile=newFile("d:"+File.separator+"hello.zip"); FileoutFile=newFile("d:"+File.separator+"unZipFile.txt"); ZipFilezipFile=newZipFile(file); ZipEntryentry=zipFile.getEntry("hello.txt"); InputStreaminput=zipFile.getInputStream(entry); OutputStreamoutput=newFileOutputStream(outFile); inttemp=0; while((temp=input.read())!=-1){ output.write(temp); } input.close(); output.close(); } }

【运行结果】:

解压缩之前:

这个压缩文件还是175字节

解压之后产生:

又回到了56字节,表示郁闷。

现在让我们来解压一个压缩文件中包含多个文件的情况吧

ZipInputStream类

当我们需要解压缩多个文件的时候,ZipEntry就无法使用了,如果想操作更加复杂的压缩文件,我们就必须使用ZipInputStream类

importjava.io.File; importjava.io.FileInputStream; importjava.io.FileOutputStream; importjava.io.IOException; importjava.io.InputStream; importjava.io.OutputStream; importjava.util.zip.ZipEntry; importjava.util.zip.ZipFile; importjava.util.zip.ZipInputStream; /** *解压缩一个压缩文件中包含多个文件的情况 **/ publicclassZipFileDemo3{ publicstaticvoidmain(String[]args)throwsIOException{ Filefile=newFile("d:"+File.separator+"zipFile.zip"); FileoutFile=null; ZipFilezipFile=newZipFile(file); ZipInputStreamzipInput=newZipInputStream(newFileInputStream(file)); ZipEntryentry=null; InputStreaminput=null; OutputStreamoutput=null; while((entry=zipInput.getNextEntry())!=null){ System.out.println("解压缩"+entry.getName()+"文件"); outFile=newFile("d:"+File.separator+entry.getName()); if(!outFile.getParentFile().exists()){ outFile.getParentFile().mkdir(); } if(!outFile.exists()){ outFile.createNewFile(); } input=zipFile.getInputStream(entry); output=newFileOutputStream(outFile); inttemp=0; while((temp=input.read())!=-1){ output.write(temp); } input.close(); output.close(); } } }

【运行结果】:

被解压的文件:

解压之后再D盘下会出现一个temp文件夹,里面内容:

PushBackInputStream回退流 importjava.io.ByteArrayInputStream; importjava.io.IOException; importjava.io.PushbackInputStream; /** *回退流操作 **/ publicclassPushBackInputStreamDemo{ publicstaticvoidmain(String[]args)throwsIOException{ Stringstr="hello,rollenholt"; PushbackInputStreampush=null; ByteArrayInputStreambat=null; bat=newByteArrayInputStream(str.getBytes()); push=newPushbackInputStream(bat); inttemp=0; while((temp=push.read())!=-1){ if(temp==,){ push.unread(temp); temp=push.read(); System.out.print("(回退"+(char)temp+")"); }else{ System.out.print((char)temp); } } } }

【运行结果】:

hello(回退,)rollenholt

/** *取得本地的默认编码 **/ publicclassCharSetDemo{ publicstaticvoidmain(String[]args){ System.out.println("系统默认编码为:"+System.getProperty("file.encoding")); } }

【运行结果】:

系统默认编码为:GBK

乱码的产生:

importjava.io.File; importjava.io.FileOutputStream; importjava.io.IOException; importjava.io.OutputStream; /** *乱码的产生 **/ publicclassCharSetDemo2{ publicstaticvoidmain(String[]args)throwsIOException{ Filefile=newFile("d:"+File.separator+"hello.txt"); OutputStreamout=newFileOutputStream(file); byte[]bytes="你好".getBytes("ISO8859-1"); out.write(bytes); out.close(); } }

【运行结果】:

??

一般情况下产生乱码,都是由于编码不一致的问题。

对象的序列化

对象序列化就是把一个对象变为二进制数据流的一种方法。

一个类要想被序列化,就行必须实现java.io.Serializable接口。虽然这个接口中没有任何方法,就如同之前的cloneable接口一样。实现了这个接口之后,就表示这个类具有被序列化的能力。

先让我们实现一个具有序列化能力的类吧:

importjava.io.*; /** *实现具有序列化能力的类 **/ publicclassSerializableDemoimplementsSerializable{ publicSerializableDemo(){ } publicSerializableDemo(Stringname,intage){ this.name=name; this.age=age; } @Override publicStringtoString(){ return"姓名:"+name+"年龄:"+age; } privateStringname; privateintage; }

这个类就具有实现序列化能力,

在继续将序列化之前,先将一下ObjectInputStream和ObjectOutputStream这两个类

先给一个ObjectOutputStream的例子吧:

importjava.io.Serializable; importjava.io.File; importjava.io.FileOutputStream; importjava.io.IOException; importjava.io.ObjectOutputStream; /** *实现具有序列化能力的类 **/ publicclassPersonimplementsSerializable{ publicPerson(){ } publicPerson(Stringname,intage){ this.name=name; this.age=age; } @Override publicStringtoString(){ return"姓名:"+name+"年龄:"+age; } privateStringname; privateintage; } /** *示范ObjectOutputStream **/ publicclassObjectOutputStreamDemo{ publicstaticvoidmain(String[]args)throwsIOException{ Filefile=newFile("d:"+File.separator+"hello.txt"); ObjectOutputStreamoos=newObjectOutputStream(newFileOutputStream( file)); oos.writeObject(newPerson("rollen",20)); oos.close(); } }

【运行结果】:

当我们查看产生的hello.txt的时候,看到的是乱码,呵呵。因为是二进制文件。

虽然我们不能直接查看里面的内容,但是我们可以使用ObjectInputStream类查看:

importjava.io.File; importjava.io.FileInputStream; importjava.io.ObjectInputStream; /** *ObjectInputStream示范 **/ publicclassObjectInputStreamDemo{ publicstaticvoidmain(String[]args)throwsException{ Filefile=newFile("d:"+File.separator+"hello.txt"); ObjectInputStreaminput=newObjectInputStream(newFileInputStream( file)); Objectobj=input.readObject(); input.close(); System.out.println(obj); } }

【运行结果】

姓名:rollen年龄:20

到底序列化什么内容呢?

其实只有属性会被序列化。

Externalizable接口

被Serializable接口声明的类的对象的属性都将被序列化,但是如果想自定义序列化的内容的时候,就需要实现Externalizable接口。

当一个类要使用Externalizable这个接口的时候,这个类中必须要有一个无参的构造函数,如果没有的话,在构造的时候会产生异常,这是因为在反序列话的时候会默认调用无参的构造函数。

现在我们来演示一下序列化和反序列话:

packageIO; importjava.io.Externalizable; importjava.io.File; importjava.io.FileInputStream; importjava.io.FileOutputStream; importjava.io.IOException; importjava.io.ObjectInput; importjava.io.ObjectInputStream; importjava.io.ObjectOutput; importjava.io.ObjectOutputStream; /** *序列化和反序列化的操作 **/ publicclassExternalizableDemo{ publicstaticvoidmain(String[]args)throwsException{ ser();//序列化 dser();//反序列话 } publicstaticvoidser()throwsException{ Filefile=newFile("d:"+File.separator+"hello.txt"); ObjectOutputStreamout=newObjectOutputStream(newFileOutputStream( file)); out.writeObject(newPerson("rollen",20)); out.close(); } publicstaticvoiddser()throwsException{ Filefile=newFile("d:"+File.separator+"hello.txt"); ObjectInputStreaminput=newObjectInputStream(newFileInputStream( file)); Objectobj=input.readObject(); input.close(); System.out.println(obj); } } classPersonimplementsExternalizable{ publicPerson(){ } publicPerson(Stringname,intage){ this.name=name; this.age=age; } @Override publicStringtoString(){ return"姓名:"+name+"年龄:"+age; } //复写这个方法,根据需要可以保存的属性或者具体内容,在序列化的时候使用 @Override publicvoidwriteExternal(ObjectOutputout)throwsIOException{ out.writeObject(this.name); out.writeInt(age); } //复写这个方法,根据需要读取内容反序列话的时候需要 @Override publicvoidreadExternal(ObjectInputin)throwsIOException, ClassNotFoundException{ this.name=(String)in.readObject(); this.age=in.readInt(); } privateStringname; privateintage; }

【运行结果】:

姓名:rollen年龄:20

本例中,我们将全部的属性都保留了下来,

Serializable接口实现的操作其实是吧一个对象中的全部属性进行序列化,当然也可以使用我们上使用是Externalizable接口以实现部分属性的序列化,但是这样的操作比较麻烦,

当我们使用Serializable接口实现序列化操作的时候,如果一个对象的某一个属性不想被序列化保存下来,那么我们可以使用transient关键字进行说明:

下面举一个例子:

packageIO; importjava.io.File; importjava.io.FileInputStream; importjava.io.FileOutputStream; importjava.io.ObjectInputStream; importjava.io.ObjectOutputStream; importjava.io.Serializable; /** *序列化和反序列化的操作 **/ publicclassserDemo{ publicstaticvoidmain(String[]args)throwsException{ ser();//序列化 dser();//反序列话 } publicstaticvoidser()throwsException{ Filefile=newFile("d:"+File.separator+"hello.txt"); ObjectOutputStreamout=newObjectOutputStream(newFileOutputStream( file)); out.writeObject(newPerson1("rollen",20)); out.close(); } publicstaticvoiddser()throwsException{ Filefile=newFile("d:"+File.separator+"hello.txt"); ObjectInputStreaminput=newObjectInputStream(newFileInputStream( file)); Objectobj=input.readObject(); input.close(); System.out.println(obj); } } classPerson1implementsSerializable{ publicPerson1(){ } publicPerson1(Stringname,intage){ this.name=name; this.age=age; } @Override publicStringtoString(){ return"姓名:"+name+"年龄:"+age; } //注意这里 privatetransientStringname; privateintage; }

【运行结果】:

姓名:null年龄:20

最后在给一个序列化一组对象的例子吧:

importjava.io.File; importjava.io.FileInputStream; importjava.io.FileOutputStream; importjava.io.ObjectInputStream; importjava.io.ObjectOutputStream; importjava.io.Serializable; /** *序列化一组对象 **/ publicclassSerDemo1{ publicstaticvoidmain(String[]args)throwsException{ Student[]stu={newStudent("hello",20),newStudent("world",30), newStudent("rollen",40)}; ser(stu); Object[]obj=dser(); for(inti=0;i<obj.length;++i){ Students=(Student)obj[i]; System.out.println(s); } } //序列化 publicstaticvoidser(Object[]obj)throwsException{ Filefile=newFile("d:"+File.separator+"hello.txt"); ObjectOutputStreamout=newObjectOutputStream(newFileOutputStream( file)); out.writeObject(obj); out.close(); } //反序列化 publicstaticObject[]dser()throwsException{ Filefile=newFile("d:"+File.separator+"hello.txt"); ObjectInputStreaminput=newObjectInputStream(newFileInputStream( file)); Object[]obj=(Object[])input.readObject(); input.close(); returnobj; } } classStudentimplementsSerializable{ publicStudent(){ } publicStudent(Stringname,intage){ this.name=name; this.age=age; } @Override publicStringtoString(){ return"姓名:"+name+"年龄:"+age; } privateStringname; privateintage; }

【运行结果】:

姓名:hello年龄:20

姓名:world年龄:30

姓名:rollen年龄:40

写在最后:本文章没有涉及java.nio,等我有时间,我自会补上的,欢迎大家关注我的博客,大家一起交流学习。

本文内容总结:字节流,字符流,关于字节流和字符流的区别,使用字节流好还是字符流好呢?,

原文链接:https://www.cnblogs.com/rollenholt/archive/2011/09/11/2173787.html