java字符流的构造方法_Java IO流——字节流和字符流详解

原标题:Java IO流——字节流和字符流详解

一、字节流

1)输入和输出流

首先,字节流要进行读和写,也就是输入和输出,所以它有两个抽象的父类InputStream、OutputStream。

InputStream抽象了应用程序读取数据的方式,即输入流。

OutputStream抽象了应用程序写出数据的方式,即输出流。

2)读写结束

在字节流中当读写结束,达到文件结尾时,称为EOF = End或者读到-1就读到结尾。

3)输入流基本方法

首先我们要清楚输入流是什么。比如通过我们的键盘在文本文件上输入内容,这个过程键盘充当的就是输入流,而不是输出流。因为键盘的功能是将内容输入到系统,系统再写入到文件上。以下是输入流的基本方法read():

intb = in.read(); //读取一个字节无符号填充到int低八位。-1是EOF。in.read( byte[] buf); //读取数据填充到字节数组buf中。返回的是读到的字节个数。in.read( byte[] buf, intstart, intsize) //读取数据到字节数组buf从buf的start位置开始存放size长度分数据

其中in是InputStream抽象类的实例,可以发现这个方法和RandomAccessFile类中的read()方法差不多,因为两者都是通过字节来读取的。

4)输出流基本方法

输出流是进行写的操作,其基本操作方法是write(),可以将此方法与输入read()方法一 一去对应,更好理解。

1out.write( intb) //写出一个byte到流,b的低8位2out.write( byte[] buf) //将buf字节数组都写到流3out.write( byte[] buf, intstart, intsize) //字节数组buf从start位置开始写size长度的字节到流

了解了InputStream、OutputStream的基本操作方法后,再来看看它们两个的“孩子”FileInputStream和FileOutputStream。

这两个子类具体实现了在文件上读取和写入数据的操作,日程编程中更多的是使用这两个类。

二、FileInputStream和FileOutputStream类的使用

—————–FileInputStream类的使用

1.使用read()方法读取文件

/** * 读取指定文件内容,按照16进制输出到控制台 * 并且每输出10个byte换行 *@throwsFileNotFoundException */publicstaticvoidprintHex(String fileName) throwsIOException{ //把文件作为字节流进行读操作FileInputStream in= newFileInputStream(fileName); intb; intcount= 0; //计数读到的个数while((b=in.read())!=- 1){ if(b<= 0xf){ //单位数前面补0System.out.println( "0"); } System.out.print(Integer.toHexString(b& 0xff)+ " "); if(++count% 10== 0){ System.out.println(); } } in.close(); //一定要关闭流}

运行结果(随便一个文件来测试的):

010375e991b86ebdbe8e4249ef621d96.png

注意:

- FileInputStream()构造函数可以通过文件名(String)也可以通过File对象。上面的案例是使用文件名来构造的。

- (b=in.read())!=-1 通过读到-1来判断是否读到文件结尾。

- in.close() 使用完IO流的对象一定要关闭流,养成好习惯很重要。

2.使用read(byte[] buf,int start, int size)方法读取文件

上述方法只能一个一个字节读取,对于较大的文件效率太低,推荐使用这个方法来一次性读取文件。

publicstaticvoidprintHexByBytes(String fileName) throws IOException{ FileInputStream in= newFileInputStream(fileName); byte[] buf= newbyte[ 20* 1024]; //开辟一个20k大小的字节数组/* * 从in中批量读取字节,放入到buf这个字节数组中 * 从第0个位置开始放,最多放buf.length个 * 返回的是读到的字节个数 *///一次性读完的情况intcount= in.read(buf, 0, buf.length); intj= 1; for( inti= 0;i

read(byte[] buf,int start, int size)返回的是读到的字节个数,即buf字节数组的有效长度,所以输出buf数组时用的长度是count而不是buf.length,因为我们不知道文件大小和数组大小的关系,上述方法适用于文件大小不超过数组大小的情况下,一次性把文件内容读取到数组里,这里就有一个问题了,如果文件大小超过数组大小,那又该如何读取才能把文件全部读完呢??

我们知道读到-1就是读到文件末,所以还是利用while循环重复读取直到读到-1结束循环,把上述代码修改后如下:

publicstaticvoidprintHexByBytes(String fileName) throws IOException{ FileInputStream in= newFileInputStream(fileName); byte[] buf= newbyte[ 20* 1024]; //开辟一个20k大小的字节数组/* * 从in中批量读取字节,放入到buf这个字节数组中 * 从第0个位置开始放,最多放buf.length个 * 返回的是读到的字节个数 */intj= 1; //一个字节数组读不完的情况,用while循环重复利用此数组直到读到文件末=-1intb= 0; while((b= in.read(buf, 0, buf.length))!=- 1){ for( inti= 0;i

好了,我们用一个大于数组的文件来测试一下结果(太长,只截图末尾):

bc5f3acb74d9587e98003dc04affdc44.png

大家可以比较两者的不同,第二种优化后更适合日常的使用,因为无论文件大小我们都可以一次性直接读完。

—————–FileOutputStream类的使用

FileOutputStream类和FileInputStream类的使用相类似,它实现了向文件中写出btye数据的方法。里面的一些细节跟FileInputStream差不多的我就不提了,大家自己可以理解的。

1.构造方法

FileOutputStream类构造时根据不同的情况可以使用不同的方法构造,如:

1//如果该文件不存在,则直接创建,如果存在,删除后创建2FileOutputStream out= newFileOutputStream( "demo/new1.txt"); //以路径名称构造1//如果该文件不存在,则直接创建,如果存在,在文件后追加内容2FileOutputStream out= newFileOutputStream( "demo/new1.txt", true);

更多内容可以查询API。

2.使用write()方法写入文件

write()方法和read()相似,只能操作一个字节,即只能写入一个字节。例如:

1out.wirte(‘A’) ;//写出了‘A’的低八位2int a= 10;//wirte只能写八位,那么写一个int需要写4次,每次八位3out.write(a>>> 24) ;4out.write(a>>> 16) ;5out.write(a>>> 8) ;6out.wirte(a) ;

每次只写一个字节,显然是不效率的,OutputStream当然跟InputStream一样可以直接对byte数组操作。

3.使用write(byte[] buf,int start, int size)方法写入文件

意义:把byte[]数组从start位置到size位置结束长度的字节写入到文件中。

语法格式和read相同,不多说明

三、FileInputStream和FileOutputStream结合案例

了解了InputStream和OutputStream的使用方法,这次结合两者来写一个复制文件的方法。

publicstaticvoidcopyFile(File srcFile,File destFile)throws IOException{ if(!srcFile.exists()){ thrownewIllegalArgumentException( "文件:"+srcFile+ "不存在"); } if(!srcFile.isFile()){ thrownewIllegalArgumentException(srcFile+ "不是一个文件"); } FileInputStream in= newFileInputStream(srcFile); FileOutputStream out= newFileOutputStream(destFile); byte[] buf= newbyte[ 8* 1024]; intb; while((b= in.read(buf, 0, buf.length))!=- 1){ out.write(buf, 0, b); out.flush(); //最好加上} in.close(); out.close(); }

测试文件案例:

try {IOUtil.copyFile(new File("C: \\Users \\acer \\workspace \\encode \\new4 \\test1"), new File("C: \\Users \\acer \\workspace \\encode \\new4 \\test2")); }catch (IOException e) {// TODO Auto-generated catch block e.printStackTrace(); }}

运行结果:

9e39db86815f9d18fa727d7e6d4ff0ce.png

复制成功!

四、DataInputStream和DataOutputStream的使用

DataInputStream、DataOutputStream 是对“流”功能的扩展,可以更加方便地读取int,long。字符等类型的数据。

对于DataOutputStream而言,它多了一些方法,如

writeInt()/wirteDouble()/writeUTF()

这些方法其本质都是通过write()方法来完成的,这些方法都是经过包装,方便我们的使用而来的。

1.构造方法

以DataOutputStream为例,构造方法内的对象是OutputStream类型的对象,我们可以通过构造FileOutputStream对象来使用。

1Stringfile= "demo/data.txt"; 2DataOutputStream dos= newDataOutputStream( newFileOutputStream( file));

2.write方法使用

dos .writeInt( 10) ;dos .writeInt(- 10) ;dos .writeLong( 10l) ;dos .writeDouble( 10.0) ;//采用utf- 8编码写出 dos .writeUTF( "中国") ;//采用utf- 16be(java编码格式)写出 dos .writeChars( "中国") ;

3.read方法使用

以上述的写方法对立,看下面例子用来读出刚刚写的文件

String file= "demo/data.txt";IOUtil .printHex(file) ;DataInputStream dis=new DataInputStream(new FileInputStream(file)) ;int i=dis .readInt() ;System .out.println(i) ;i=dis .readInt() ;System .out.println(i) ;long l=dis .readLong() ;System .out.println(l) ;double d=dis .readDouble() ;System .out.println(d) ;String s= dis .readUTF() ;System .out.println(s) ;dis .close() ;

运行结果:

96b8fe9a7c1002bf5fbd2d1247b025a0.png

总结:DataInputStream和DataOutputStream其实是对FileInputStream和FileOutputStream进行了包装,通过嵌套方便我们使用FileInputStream和FileOutputStream的读写操作,它们还有很多其他方法,大家可以查询API。

注意:进行读操作的时候如果类型不匹配会出错!

五、字节流的缓冲流BufferredInputStresam&BufferredOutputStresam

这两个流类为IO提供了带缓冲区的操作,一般打开文件进行写入或读取操作时,都会加上缓冲,这种流模式提高了IO的性能。

从应用程序中把输入放入文件,相当于将一缸水倒入另一个缸中:

FileOutputStream—->write()方法相当于一滴一滴地把水“转移”过去

DataOutputStream—->write()XXX方法会方便一些,相当于一瓢一瓢地把水“转移”过去

BufferedOutputStream—->write方法更方便,相当于一瓢一瓢水先放入一个桶中(缓冲区),再从桶中倒入到一个缸中。提高了性能,推荐使用!

上述提到过用FileInputStream和FileOutputStream结合写的一个拷贝文件的案例,这次通过字节的缓冲流对上述案例进行修改,观察两者的区别和优劣。

主函数测试:

try {long start=System.currentTimeMillis(); //IOUtil.copyFile(new File("C: \\Users \\acer \\Desktop \\学习路径.docx"), new File("C: \\Users \\acer \\Desktop \\复制文本.docx")); long end=System.currentTimeMillis(); System.out.println(end-start); }catch (IOException e) {// TODO Auto-generated catch block e.printStackTrace(); }

(1)单字节进行文件的拷贝,利用带缓冲的字节流

/* * 单字节进行文件的拷贝,利用带缓冲的字节流 */publicstaticvoidcopyFileByBuffer(File srcFile,File destFile) throwsIOException{ if(!srcFile.exists()){ thrownewIllegalArgumentException( "文件:"+srcFile+ "不存在"); } if(!srcFile.isFile()){ thrownewIllegalArgumentException(srcFile+ "不是一个文件"); } BufferedInputStream bis= newBufferedInputStream( newFileInputStream(srcFile)); BufferedOutputStream bos= newBufferedOutputStream( newFileOutputStream(destFile)); intc; while((c=bis.read())!=- 1){ bos.write(c); bos.flush(); //刷新缓冲区} bis.close(); bos.close(); }

运行结果(效率):

(2)单字节不带缓冲进行文件拷贝

/* * 单字节不带缓冲进行文件拷贝 */publicstaticvoidcopyFileByByte(File srcFile,File destFile)throws IOException{ if(!srcFile.exists()){ thrownewIllegalArgumentException( "文件:"+srcFile+ "不存在"); } if(!srcFile.isFile()){ thrownewIllegalArgumentException(srcFile+ "不是一个文件"); } FileInputStream in= newFileInputStream(srcFile); FileOutputStream out= newFileOutputStream(destFile); intc; while((c= in.read())!=- 1){ out.write(c); out.flush(); //不带缓冲,可加可不加} in.close(); out.close(); }

运行结果(效率):

(3)批量字节进行文件的拷贝,不带缓冲的字节流(就是上面第三点最初的案例的代码)

/* * 字节批量拷贝文件,不带缓冲 Java学习交流QQ群:589809992 我们一起学Java! */publicstaticvoidcopyFile(File srcFile,File destFile)throws IOException{ if(!srcFile.exists()){ thrownewIllegalArgumentException( "文件:"+srcFile+ "不存在"); } if(!srcFile.isFile()){ thrownewIllegalArgumentException(srcFile+ "不是一个文件"); } FileInputStream in= newFileInputStream(srcFile); FileOutputStream out= newFileOutputStream(destFile); byte[] buf= newbyte[ 8* 1024]; intb; while((b= in.read(buf, 0, buf.length))!=- 1){ out.write(buf, 0, b); out.flush(); //最好加上} in.close(); out.close(); }

运行结果(效率):

(4)批量字节进行文件的拷贝,带缓冲的字节流(效率最高,推荐使用!!)

/* * 多字节进行文件的拷贝,利用带缓冲的字节流 */publicstaticvoidcopyFileByBuffers(File srcFile,File destFile) throwsIOException{ if(!srcFile.exists()){ thrownewIllegalArgumentException( "文件:"+srcFile+ "不存在"); } if(!srcFile.isFile()){ thrownewIllegalArgumentException(srcFile+ "不是一个文件"); } BufferedInputStream bis= newBufferedInputStream( newFileInputStream(srcFile)); BufferedOutputStream bos= newBufferedOutputStream( newFileOutputStream(destFile)); byte[] buf= newbyte[ 20* 1024]; intc; while((c=bis.read(buf, 0, buf.length))!=- 1){ bos.write(buf, 0, c); bos.flush(); //刷新缓冲区} bis.close(); bos.close(); }

运行结果(效率):

注意:

- 批量读取或写入字节,带字节缓冲流的效率最高,推荐使用此方法。

当使用字节缓冲流时,写入操作完毕后必须刷新缓冲区,flush()。

不使用字节缓冲流时,flush()可以不加,但是最好加上去。六、字符流

首先我们需要了解以下概念。

1)需要了解编码问题

2)认识文本和文本文件

java的文本(char)是16位无符号整数,是字符的unicode编码(双字节编码)

文件是byte byte byte…的数据序列

文本文件是文本(char)序列按照某种编码方案(utf-8,utf-16be,gbk)序列化byte的存储

3)字符流(Reader Writer)

字符的处理,一次处理一个字符;

字符的底层依然是基本的字节序列;

4)字符流的基本实现

InputStreamReader:完成byte流解析成char流,按照编码解析。

OutputStreamWriter:提供char流到byte流,按照编码处理。

————————-Reader和Writer的基本使用——————————-

String file1= "C:\\Users\\acer\\workspace\\encode\\new4\\test1"; String file2= "C:\\Users\\acer\\workspace\\encode\\new4\\test2"; InputStreamReader isr= newInputStreamReader( newFileInputStream(file1)); OutputStreamWriter osw= newOutputStreamWriter( newFileOutputStream(file2)); // int c;// while((c=isr.read())!=-1){// System.out.print((char)c);// }char[] buffer= newchar[ 8* 1024]; intc; //批量读取,放入buffer这个字符数组,从第0个位置到数组长度//返回的是读到的字符个数while((c=isr.read(buffer, 0,buffer.length))!=- 1){ String s= newString(buffer, 0,c); //将char类型数组转化为String字符串System. out.println(s); osw.write(buffer, 0,c); osw.flush(); //osw.write(s);//osw.flush();} isr.close(); osw.close();

注意:

字符流操作的是文本文件,不能操作其他类型的文件!!

默认按照GBK编码来解析(项目默认编码),操作文本文件的时候,要写文件本身的编码格式(在构造函数时在后面加上编码格式)!!

字符流和字节流的区别主要是操作的对象不同,还有字符流是以字符为单位来读取和写入文件的,而字节流是以字节或者字节数组来进行操作的!!

在使用字符流的时候要额外注意文件的编码格式,一不小心就会造成乱码!七、字符流的文件读写流FileWriter和FileReader

跟字节流的FileInputStream和FileOutputStream类相类似,字符流也有相应的文件读写流FileWriter和FileReader类,这两个类主要是对文本文件进行读写操作。

FileReader/FileWriter:可以直接写文件名的路径。

与InputStreamReader相比坏处:无法指定读取和写出的编码,容易出现乱码。

1 FileReader fr = new FileReader("C: \\Users \\acer \\workspace \\encode \\new4 \\test1"); //输入流 2 FileWriter fw = new FileWriter(C: \\Users \\acer \\workspace \\encode \\new4 \\test2");//输出流 char[] buffer=new char[ 8*1024]; intc; while((c=fr. read(buffer, 0, buffer. length))!=- 1){ fw. write(buffer, 0, c); fw.flush(); } fr. close(); fw. close();

注意:FileReader和FileWriter不能增加编码参数,所以当项目和读取文件编码不同时,就会产生乱码。 这种情况下,只能回归InputStreamReader和OutputStreamWriter。

八、字符流的过滤器BufferedReader&BufferedWriter

字符流的过滤器有BufferedReader和BufferedWriter/PrintWriter

除了基本的读写功能外,它们还有一些特殊的功能。

BufferedReader—–>readLine 一次读一行,并不识别换行

BufferedWriter—–>write 一次写一行,需要换行

PrintWriter经常和BufferedReader一起使用,换行写入比BufferedWriter更方便

定义方式:

BufferedReader br = newBufferedReader( newInputStreamReader( newFileInputStream(目录的地址))) BufferedWriter br = newBufferedWriter( newInputStreamWriter( newFileOutputStream(目录的地址))) PrintWriter pw=new PrintWriter(目录/Writer/ OutputStream/ File);

使用方法:

//对文件进行读写操作 Java学习交流QQ群:589809992 我们一起学Java!Stringfile1 ="C:\\Users\\acer\\workspace\\encode\\new4\\test1"; Stringfile2 ="C:\\Users\\acer\\workspace\\encode\\new4\\test2"; BufferedReader br =newBufferedReader( newInputStreamReader( newFileInputStream(file1))); BufferedWriter bw=newBufferedWriter( newOutputStreamWriter( newFileOutputStream(file2))); Stringline; while((line =br .readLine()) !=null){ System .out .println(line); //一次读一行,并不能识别换行bw.write(line); //单独写出换行操作bw.newLine(); bw.flush(); } br .close(); bw.close(); }

在这里我们可以使用PrintWriter来代替BufferedWriter做写操作,PrintWriter相比BufferedWriter有很多优势:

构造函数方便简洁,使用灵活

构造时可以选择是否自动flush

利用println()方法可以实现自动换行,搭配BufferedReader使用更方便

使用方法:

Stringfile1= "C:\\Users\\acer\\workspace\\encode\\new4\\test1"; Stringfile2= "C:\\Users\\acer\\workspace\\encode\\new4\\test2"; BufferedReader br = newBufferedReader( newInputStreamReader( newFileInputStream(file1))); PrintWriter pw= newPrintWriter(file2); //PrintWriter pw=new PrintWriter(outputStream, autoFlush);//可以指定是否自动flushStringline; while((line=br.readLine())!= null){ System.out.println(line); //一次读一行,并不能识别换行pw.println(line); //自动换行pw.flush(); //指定自动flush后不需要写} br.close(); pw.close(); }

注意:

可以使用BufferedReader的readLine()方法一次读入一行,为字符串形式,用null判断是否读到结尾。

使用BufferedWriter的write()方法写入文件,每次写入后需要调用flush()方法清空缓冲区;PrintWriter在构造时可以指定自动flush,不需要再调用flush方法。

在写入时需要注意写入的数据中会丢失换行,可以在每次写入后调用BufferedReader的newLine()方法或改用PrintWriter的println()方法补充换行。

通常将PrintWriter配合BufferedWriter使用。(PrintWriter的构造方法,及使用方式更为简单)。

—————–更多java流的操作和内容请自行查阅API————————返回搜狐,查看更多

责任编辑:

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
根据提供的引用内容,可以了解到Java IO分为节流字符两种类型。其中节流节为单位进行读写,而字符字符为单位进行读写。下面是Java IO节流构造方法和使用方法: 1. InputStream类是所有节输入的父类,常用方法有: - read():从输入中读取一个节的数据。 - read(byte[] b):从输入中读取一定数量的节,并将其存储在缓冲区数组b中。 - skip(long n):跳过并丢弃输入中的n个节数据。 - available():返回输入中可以被读取的节数。 2. FileInputStream类是InputStream类的子类,常用方法有: - FileInputStream(String name):创建一个文件输入,以读取具有指定名称的文件。 - read():从输入中读取一个节的数据。 - read(byte[] b):从输入中读取一定数量的节,并将其存储在缓冲区数组b中。 - skip(long n):跳过并丢弃输入中的n个节数据。 - available():返回输入中可以被读取的节数。 3. FileOutputStream类是OutputStream类的子类,常用方法有: - FileOutputStream(String name):创建一个文件输出,以写入具有指定名称的文件。 - write(int b):将指定的节写入此文件输出。 - write(byte[] b):将b.length个节从指定的节数组写入此文件输出中。 - flush():刷新此输出并强制任何缓冲的输出节被写出。 下面是一个Java IO节流复制文件的示例代码: ```java public static void main(String[] args) { try { // 创建要复制文件的节输入 InputStream inp = new FileInputStream("/Users/chenyq/Documents/learn_Java/code/file-io-app/src/test.pdf"); // 创建目标路径的节输出 OutputStream oup = new FileOutputStream("/Users/chenyq/Documents/newtest.pdf"); // 使用文件输入获取要复制文件的全部数据的节数组 byte[] arr = inp.readAllBytes(); // 使用文件输出节数组写入目标文件 oup.write(arr); System.out.println("复制成功!"); // 释放资源 inp.close(); oup.close(); } catch (IOException e) { e.printStackTrace(); } } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值