javaIO ---字节流与字符流

流的基本概念

服务器与客户端传输的就是数据流,或者说比特流。
java.io包中的字节处理流:

  • 输出字节流:OutputStream
  • 输入字节流:InputStream

字符处理流:

  • 输出字符流:Writer
  • 输出字节流:Reader

对文件的读写流程:

  1. 通过File类找到文件路径
  2. 通过字节流或字符流对对象进行实例化
  3. 利用字节流与字符流的方法实现数据的输入输出
  4. 流操作属于资源操作,必须进行关闭处理

OutputStream字节输出流

类的声明:public abstract class OutputStream extends Object implements Closeable, Flushable
有两个接口:

CloseableFlushable
jdk1.5jdk1.5
void close();void flush();

Closeable接口实现了AutoCloseable接口(jdk1.7,出现了try…catch)

OutputStream类中定义了三个内容输出的方法:

方法名作用
public abstract void write(int b)throws IOException;输出单个字节数据
public void write(byte b[])throws IOException;输出一组字节数据
*public void write(byte b[],int off,int len)throws IOException;输出部分字节数据

(off参数表示偏移量,一般为0.)

OutputStream类是抽象类,实现其方法需要通过子类向上转型。那么子类(FileOutputStream)的关注点主要放在构造方法上即可。
例:FileOutputStream
【覆盖】构造方法:public FileOutputStream(File file)throws FileNotFoundException
【追加】构造方法:public FileOutputStream(File file,boolean append)throws FileNotFoundException

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;

public class OutputTest {

	public static void main(String[] args) throws Exception {
		File file=new File("F:\\course\\output.txt");
		if(!file.getParentFile().exists()) {
			file.getParentFile().mkdirs();
		}
		OutputStream out=new FileOutputStream(file);
		String str="hello first file 操作";
		out.write(str.getBytes());
		out.close();
	}

}

由于OutputStream是AutoCloseable的子类,所以可以执行自动关闭处理。
但是否执行自动关闭取决于项目的整体结构。

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

public class OutputTest {

	public static void main(String[] args) throws Exception {
		File file=new File("F:\\course\\output.txt");
		if(!file.getParentFile().exists()) {
			file.getParentFile().mkdirs();
		}
		try(OutputStream out=new FileOutputStream(file,true)){
			String str="hello first file 操作\r\n";//\n是换行,\r\n是标准换行
			out.write(str.getBytes());
		}catch(IOException e) {
			e.printStackTrace();
		}
	}

}

InputStream字节输入流

类的声明:public abstract class InputStream extends Object implements Closeable
主要方法:

方法名作用
public abstract int read(int b)throws IOException;输出单个字节数据(如果数据读取到末尾,返回“-1”)
*public int read(byte b[])throws IOException;输出一组字节数据(返回值为读取数据的个数,如果没有数据(已经读取到底)返回“-1”)
public int read(byte b[],int off,int len)throws IOException;输出一组字节数据的部分

InputStream是抽象类,依靠子类FileInputStream向上转型实现。
例:

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;

public class InputTest {

	public static void main(String[] args) throws Exception {
		File file=new File("F:\\course\\Output.txt");
		if(file.exists()) {
			InputStream in=new FileInputStream(file);
			byte bt[]=new byte[1024];
			int len = in.read(bt);
			System.out.println("["+new String(bt,0,len)+"]");
			in.close();
		}
	}

}

字节输入流的问题,使用read()方法只能以字节数组为主进行接收。

jdk1.9中出现了一个方法:public byte[] readAllBytes()throws IOException;
如果要读取的内容很大,会使程序崩溃。最多10K。

Writer字符输出流

jdk1.1,java.io包
类声明:public abstract class Writer extends Object implements Appendable, Closeable, Flushable

接口名版本方法
Closeablejdk1.5void close();
Flushablejdk1.5void flush();
Appendablejdk1.5void append();

输出方法:

方法作用
public void write(char[] cbuf)throws IOException;输出字符数组
public void write(String str)throws IOException;输出字符串

范例:使用write输出:

import java.io.File;
import java.io.FileWriter;
import java.io.Writer;

public class WriterTest {

	public static void main(String[] args) throws Exception {
		File file = new File("F:/course/file.txt");
		if(!file.getParentFile().exists()) {
			file.getParentFile().mkdirs();
		}
		Writer out=new FileWriter(file,true);
		String str="?????????我被冷落了QAQ\n";
		out.append(str);
		out.close();
	}

}

使用Writer输出的最大优势在于可以使用字符串完成,字符流最大的优势在处理中文数据上。

Reader字符输入流

类声明:public abstract class Reader extends Object implements Readable, Closeable

接口名版本方法
Closeablejdk1.5void close();
Readablejdk1.5void read();

Reader里面没有提供整个字符串的输入处理操作,只能进行字符数组进行接收。

方法名作用
public abstract int read()throws IOException;输出单个字节数据(如果数据读取到末尾,返回“-1”)
*public int read(char[] cbuf )throws IOException;输出一组字节数据(返回值为读取数据的个数,如果没有数据(已经读取到底)返回“-1”)
public int read(char[] cbuf ,int off,int len)throws IOException;输出一组字节数据的部分

范例:实现数据读取

import java.io.File;
import java.io.FileReader;
import java.io.Reader;

public class ReaderTest {

	public static void main(String[] args) throws Exception {
		File file=new File("F:/course/file.txt");
		if(file.exists()) {
			Reader in=new FileReader(file);
			char ch[]=new char[1024];
			int len=in.read(ch);
			System.out.println("["+new String(ch,0,len)+"]");
			in.close();
		}
	}

}

字节流与字符流的区别

输出流比较:
OutputStream类中,不close()关闭文件内容正常输出。
Writer类中,不使用close()文件内容无法输出。
原因:Writer使用了缓存区,使用close方法会强制刷新缓冲区,close时会将内容进行刷新,否则不刷新。如果想要在不使用close的情况下使结果输出可以使用flush方法强制清空。

import java.io.File;
import java.io.FileWriter;
import java.io.Writer;

public class WriterTest {

	public static void main(String[] args) throws Exception {
		File file = new File("F:/course/file.txt");
		if(!file.getParentFile().exists()) {
			file.getParentFile().mkdirs();
		}
		Writer out=new FileWriter(file,true);
		String str="?????????我被冷落了QAQ\n";
		out.append(str);
		out.flush();//强制刷新
		//out.close();
	}

}

字节流处理的时候不会使用缓冲区,但是字符流在进行处理的时候会使用到缓冲区。使用到缓冲区的字符流更加适合中文的处理。
字节流和字符流的处理方式相似,IO很多情况下是使用二进制,所以大都以字节流为主。

转换流

实现字节流和字符流的功能转换。
两个转换流的类:InputStreamReader,OutputStreamWriter
类的声明:

OutputStreamReaderInputStreamWriter
public class OutputStreamWriter extends Writerpublic class InputStreamReader extends Reader
public OutputStreamWriter​(OutputStream out)public InputStreamReader​(InputStream in)

在这里插入图片描述
通过类的结构和构造方法可以发现,转换处理本质是对象的转型和构造方法的接收,就是通过字节流对象通过向上转型变成字符流对象。

转换流主要是为了让我们明确的对结构分析处理。
FileReader和FileWriter的继承关系:

FileReaderFileWriter
public class FileReader extends InputStreamReaderpublic class FileWriter extends OutputStreamWriter

在这里插入图片描述

案例:文件拷贝

需求分析:

  1. 实现各种文件的拷贝,使用字节流。
  2. 大文件的拷贝问题。

方案:

  1. 使用InputStream将文件中所有的内容读到程序中,才一次性写入目标文件。(如果文件很大会让程序崩溃)
  2. 采用部分拷贝。

使用方法:

  • public void write(byte b[],int off,int len)throws IOException;
  • public void read(byte b[])throws IOException;

实现文件拷贝处理:(原始方法)

package wzr.study09.io;

import java.io.*;

public class FileUtilTest {

	public static void main(String[] args) throws Exception {
		if(args.length!=2) {
			System.out.println("格式:java filename str1 str2");
			System.exit(1);
		}
		long start=System.currentTimeMillis();
		FileUtil fu=new FileUtil(args[0],args[1]);
		System.out.println(fu.copy()?"文件拷贝成功":"文件拷贝失败");
		
		long end=System.currentTimeMillis();
		System.out.println("拷贝完成的时间:"+(end-start));
	}

}
class FileUtil{
	private File srcfile;
	private File desfile;
	
	public FileUtil(File src,File des) {
		srcfile=src;
		desfile=des;
	}
	public FileUtil(String src,String des) {
		this(new File(src), new File(des));
	}
	public boolean copy() throws Exception {
		if(!srcfile.exists()) {
			System.out.println("拷贝的源文件不存在");
			return false;
		}
		if(!desfile.getParentFile().exists()) {
			desfile.getParentFile().mkdirs();
		}
		byte bt[]=new byte[1024];
		InputStream input=null;
		OutputStream output=null;
		try {
			input=new FileInputStream(srcfile);
			output=new FileOutputStream(desfile);
			
			int len=0;
			while((len=input.read(bt))!=-1) {
				output.write(bt,0,len);
			}
			return true;
			
		}catch(Exception e) {
			throw e;
		}finally {
			if(input!=null) {
				input.close();
			}
			if(output!=null) {
				output.close();
			}
		}
	}
}

jdk1.9开始,输入流InputStream和Reader都追加有缓存的处理方法
InputStream:public long transferTo(OutputStream out)throws Exception;
OutputStream:public long transferTo(Writer out)throws Exception;
使用转存的方式处理:

package wzr.study09.io;

import java.io.*;

public class FileUtilTest {

	public static void main(String[] args) throws Exception {
		if(args.length!=2) {
			System.out.println("格式:java filename str1 str2");
			System.exit(1);
		}
		long start=System.currentTimeMillis();
		FileUtil fu=new FileUtil(args[0],args[1]);
		System.out.println(fu.copy()?"文件拷贝成功":"文件拷贝失败");
		long end=System.currentTimeMillis();
		System.out.println("拷贝完成的时间:"+(end-start));
	}

}
class FileUtil{
	private File srcfile;
	private File desfile;
	
	public FileUtil(File src,File des) {
		srcfile=src;
		desfile=des;
	}
	public FileUtil(String src,String des) {
		this(new File(src), new File(des));
	}
	public boolean copy() throws Exception {
		if(!srcfile.exists()) {
			System.out.println("拷贝的源文件不存在");
			return false;
		}
		if(!desfile.getParentFile().exists()) {
			desfile.getParentFile().mkdirs();
		}
		InputStream input=null;
		OutputStream output=null;
		try {
			input=new FileInputStream(srcfile);
			output=new FileOutputStream(desfile);
			input.transferTo(output);//没有避开文件过大的情况
			return true;
			
		}catch(Exception e) {
			throw e;
		}finally {
			if(input!=null) {
				input.close();
			}
			if(output!=null) {
				output.close();
			}
		}
	}
}

文件夹拷贝:

package wzr.study09.io;

import java.io.*;

public class FileUtilTest {

	public static void main(String[] args) throws Exception {
		if(args.length!=2) {
			System.out.println("格式:java filename str1 str2");
			System.exit(1);
		}
		long start=System.currentTimeMillis();
		FileUtil fu=new FileUtil(args[0],args[1]);
		if(new File(args[0]).isFile()) {
			System.out.println(fu.copyFile()?"文件拷贝成功":"文件拷贝失败");
		}else {
			System.out.println(fu.copyDir()?"文件夹拷贝成功":"文件夹拷贝失败");
		}
		long end=System.currentTimeMillis();
		System.out.println("拷贝完成的时间:"+(end-start));
	}

}
class FileUtil{
	private File srcfile;
	private File desfile;
	
	public FileUtil(File src,File des) {
		srcfile=src;
		desfile=des;
	}
	public FileUtil(String src,String des) {
		this(new File(src), new File(des));
	}
	public boolean copyDir() throws Exception{
		try {
			copyDirImpl(this.srcfile);
			return true;
		}catch(Exception e) {
			return false;
		}
	}
	public boolean copyFile() throws Exception {
		if(!srcfile.exists()) {
			System.out.println("拷贝的源文件不存在");
			return false;
		}
		return copyFileImpl(this.srcfile,this.desfile);
	}
	private void copyDirImpl(File file) throws Exception{
		if(file.isDirectory()) {
			File result[]=file.listFiles();
			if(result!=null) {
				for(File obj:result) {
					copyDirImpl(obj);
				}
			}
		}else {
			System.out.println(file.getPath().replace(this.srcfile.getPath()+File.separator, ""));
//			String newfilepath=file.getPath().replace(this.srcfile.getPath()+File.separator, "");
//			File newfile=new File(this.desfile,newfilepath);
//			copyFileImpl(file,newfile);
		}
	}
	private boolean copyFileImpl(File srcfile,File desfile) throws Exception{
		if(!desfile.getParentFile().exists()) {
			desfile.getParentFile().mkdirs();
		}
		byte bt[]=new byte[1024];
		InputStream input=null;
		OutputStream output=null;
		try {
			input=new FileInputStream(srcfile);
			output=new FileOutputStream(desfile);
			//input.transferTo(output);//没有避开文件过大的情况
			int len=0;
			while((len=input.read(bt))!=-1) {
				output.write(bt,0,len);
			}
			return true;
			
		}catch(Exception e) {
			return false;
		}finally {
			if(input!=null) {
				input.close();
			}
			if(output!=null) {
				output.close();
			}
		}
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值