Java中执行输出和输入操作,需要通过IO流。例如最常见的System.out.println()就是一个输出流。IO流的类比较多,但核心体系就是由File、 InputStream 、OutputStream、Reader、Writer和Serializable(接口)组成的,后续会一一详细说明。

I/O流基础概念

按照流的方向分为输入流(InputStream)与输出流(OuputStream):

  • 输入流:只能读取数据,不能写入数据。
  • 输出流:只能写入数据,不能读取数据。

因为程序是运行在内存中,以内存角度来理解输入输出概念,如下:

可以看到输入与输出是一个相对概念,数据写入文件,对于程序来说是输出流,对文件来说是输入流。但一般是以程序作为中心,所以从程序写入数据到其他位置,则是输出流,将数据读入程序中则是输入流。

简单的说就是:读取数据就是输入流,写入数据就是输出流。

按照处理的数据单位分为字节流和字符流

  • 字节流:操作的数据单元是8位的字节。InputStream、OutputStream作为抽象基类。
  • 字符流:操作的数据单元是字符。以Writer、Reader作为抽象基类。
  • 字节流可以处理所有数据文件,若处理的是纯文本数据,建议使用字符流。

IO流中的三类数据源

  • 基于磁盘文件:FileInputStream、FileOutputSteam、FileReader、FileWriter
  • 基于内存:ByteArrayInputStream ByteArrayOutputStream(ps:字节数组都是在内存中产生)
  • 基于网络:SocketInputStream、SocketOutputStream(ps:网络通信时传输数据)

根据流的作用可分为节点流和处理流

节点流:程序直接与数据源连接,和实际的输入/输出节点连接;处理流:对节点流进行包装,扩展原来的功能,由处理流执行IO操作。

处理流的作用和分类:

处理流可以隐藏底层设备上节点流的差异,无需关心数据源的来源,程序只需要通过处理流执行IO操作。处理流以节点流作为构造参数。通常情况下,推荐使用处理流来完成IO操作。

缓冲流:提供一个缓冲区,能够提高输入/输出的执行效率,减少同节点的频繁操作。例如:BufferedInputStream/BufferedOutputStream、BufferedReader/BufferWriter

转换流:将字节流转成字符流。字节流使用范围广,但字符流更方便。例如一个字节流的数据源是纯文本,转成字符流来处理会更好。InputStreamReader/OutputStreamWriter

打印输出流:打印输出指定内容,根据构造参数中的节点流来决定输出到何处。

PrintStream :打印输出字节数据。
PrintWriter : 打印输出文本数据。 

附图:JavaIO体系的全体类

介绍完基础概念后,使用IO流来完成一些简单功能:

(一)使用字节流读取本地文件

//File对象定位数据源
public static void getContent(File file) throws IOException {
//创建文件缓冲输入流
file BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
byte[] buf = new byte[];//创建字节数组,存储临时读取的数据
int len = ;//记录数据读取的长度
//循环读取数据
while((len = bis.read(buf)) != -) { //长度为-1则读取完毕
System.out.println(new String(buf,,len));
}
bis.close(); //关闭流
}

【技巧】如果数据源是纯文本数据,使用字符流效率更高。

(二)使用字符处理流读取本地文件内容

    public static void getContent(String path) throws IOException {
File f = new File(path);
if (f.exists()) { // 判断文件或目录是否存在
if (f.isFile()) {
BufferedReader br = new BufferedReader(new FileReader(path));//该缓冲流有一个readLine()独有方法
String s = null;
while ((s = br.readLine()) != null) {//readLine()每次读取一行
System.out.println(s);
}
}
}
}

该方法比上一个增加了文件判断,提高了程序的健壮性。使用了BufferedReader处理流来处理纯文本数据,比字节流更加简洁方便。

(三)使用字符流写入数据到指定文件:

public static void main(String[] args) throws IOException {
//以标准输入作为扫描来源
Scanner sc = new Scanner(System.in);
File f = new File("D:\\reviewIO\\WRITERTest.txt");
BufferedWriter bw = new BufferedWriter(new FileWriter(f));
if(!f.exists()) {
f.createNewFile();
}
while(true) {
String s = sc.nextLine();
bw.write(s);
bw.flush();
if(s.equals("结束") || s.equals("")) {
System.out.println("写入数据结束!");
return;
}
}
}

(四)使用转换流(InputStreamReader/OutputStreamWriter),对写入数据进行改进:

public static void testConvert(File f) throws IOException {
if(!f.exists()) {
f.createNewFile();
}
//以System.in作为读取的数据源,即从键盘读取
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new FileWriter(f,true)); //允许添加内容,不会清除原有数据源
String s = null;
while(!(s = br.readLine()).equals("")) {
bw.write(s);
bw.newLine();//空一行
}
bw.flush();
bw.close();
br.close();
}

因为System.in是一个InputStream对象,缓冲字符流无法直接使用,需要通过转换流将字节流转成字符流。然后使用字符输入处理流的readLine()每次读取一行,使用newLine()完成换行。

注意点:通常使用IO流写入文件时,写入的数据总会覆盖原来的数据,这是因为文件输出流默认不允许追加内容,所以需要为FileOuputStream、FileWriter的构造参数boolean append 传入true。

(五)使用字节流完成文件复制
//字节流实现文件拷贝
public static String copyFile(String src, String dest) throws IOException, ClassNotFoundException {
File srcFile = new File(src);//源文件数据源
File desFile = new File(dest);//写入到目标数据源
//数据源不存在
if(!srcFile.exists() || !desFile.exists()) {
throw new ClassNotFoundException("源文件或者拷贝目标文件地址不存在!");
}
//非文件类型
if(!srcFile.isFile() || !desFile.isFile()) {
return "源文件或者目标文件不是文件类型!";
}
InputStream is = null;
OutputStream os = null;
byte[] buf = new byte[];//缓存区
int len = ;//读取长度
try {
is = new BufferedInputStream(new FileInputStream(srcFile));//读取数据源
os = new BufferedOutputStream(new FileOutputStream(desFile));//写入到数据源
while((len = is.read(buf)) != -) { //读取长度不为-1,继续读取
os.write(buf); //读取内容之后马上写入目标数据源
}
os.flush();//输出
return "文件拷贝成功!查看拷贝文件路径:" + desFile.getPath();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
if(is != null)
is.close();
if(os != null)
os.close();
}
return "文件拷贝失败";
}
 

(六)使用打印流来完成写入数据操作:

        //输出内容的文件数据源
File f = new File("D:\\reviewIO\\PW.java");
PrintWriter pw = new PrintWriter(f);
//把指定内容打印至数据源中
pw.println("AAAAAAAAA");
pw.println("BBBBBBBBB");
pw.println("CCCCCCCCC");
pw.flush();
System.out.println("使用PrintWriter写入数据完成");
System.out.println("==========读取写入的数据==========");
BufferedReader br = new BufferedReader(new FileReader(f));
String s = null;
StringBuilder sb = new StringBuilder();//一个可变字符串
while((s = br.readLine()) != null) {
sb.append(s); //把读取的字符串组合起来
}
System.out.println(sb);
br.close();
pw.close();

一般情况下,若是输出文本数据,建议使用打印流。PrintWriter还可以指定输出文本使用何种字符集、在构造参数中指定是否自动刷新。如果不想覆盖原来的数据,使用该类的append()方法,就会在文件尾部添加内容。

(七)使用打印流来完成文本拷贝:

    // 使用打印流PrintStream来完成文件拷贝
public static void copyFile(File src, File dest) throws Exception {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(src));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(dest));
PrintStream ps = new PrintStream(bos, true);
byte[] buf = new byte[];
int len = ;
//循环读取数据,然后写入到目标文件
while ((len = bis.read(buf)) != -) {
ps.write(buf);
}
ps.close();
bos.close();
}

打印流实现文件拷贝操作和字节流差不多,除了用到打印流构造函数的不自动刷新。打印流还有一个好处就是无需检查异常。

JavaIO流(输入输出操作)的更多相关文章

  1. Java---IO加强(3)-IO流的操作规律

    一般写关于操作文件的读取的几个通用步骤!!! 1.明确源和目的. 源:InputStream Reader 一定是被读取的. 目的:OutputStream Writer 一定是被写入的. 2.处理的 ...

  2. javaIO流(三)--IO深入操作

    一.字符编码 在计算机的世界中,本质上只认识0,1的字节数据,如果要想描述一些文字的编码就需要对这些二进制的数据进行组合,就需要对二进制的数据进行组合,所以才有了现在可看见的中文显示,但是在进行编码的 ...

  3. Java学习日记之 Java-IO流

    Java中的IO流在处理上分为字节流和字符流.字节流和字符流的区别 : 1.字节流读取的时候,读到一个字节就返回一个字节:  字符流使用了字节流读到一个或多个字节(中文对应的字节数是两个,在UTF-8 ...

  4. 总结JAVA----IO流中的字节流

    对于IO流中字节流的总结 字节流的概念 由于应用程序,经常需要和文件打交道,所以Inputstream专门提供了读写文件的子类:FileInputStream和FileOutputStream类,如果 ...

  5. JavaIO流中的拷贝

    JavaIO流中对数据的操作尤为重要,掌握了基本的拷贝操作,才能将各种数据源的操作联系起来. 先来看看对文件夹的拷贝吧: /** * 利用递归实现文件夹的拷贝操作 * 分析:判断 * 是文件:调用拷贝 ...

  6. Java文件IO流的操作总结

    Java中的IO操作涉及到的概念及相关类很多,很容易弄混,今天特来整理总结一下,并附上一份完整的文件操作的代码. 概念解析 读和写 流就是管道,向管道里面写数据用输出流:write 从管道里面读数据, ...

  7. IO流常规操作

    IO流 IO就是输入输出,IO设备在计算机中起着举足轻重的作用,IO流也就是输入输出流,用来交互数据,程序和程序交互,程序也可以和网络等媒介交互. 一.IO流的分类 要分类,肯定得站得不同角度来看这个 ...

  8. javaIO流(二)--字节流与字符流

    一.流的基本概念 在java.io包中,File类是唯一一个与文件本身有关的程序处理类,但是File类只能操作文件本身,而不能操作文件内容,IO操作的核心意义在于输入和输出操作.而对于程序而言,输入和 ...

  9. Java基础 Java-IO流 深入浅出

    建议阅读 重要性由高到低 Java基础-3 吃透Java IO:字节流.字符流.缓冲流 廖雪峰Java IO Java-IO流 JAVA设计模式初探之装饰者模式 为什么我觉得 Java 的 IO 很复 ...

随机推荐

  1. Totem协议(SRP/RRP)讲解

    基本概念 •SRP:  The Totem Single-Ring Ordering and MembershipProtocol            –基于以太网的组通信协议,节点间组成单环结构 ...

  2. 简析 Tomcat 、Nginx 与 Apache 的区别

    简析 Tomcat .Nginx 与 Apache 的区别 本文讲的是简析 Tomcat .Nginx 与Apache的区别, 经常在用 apache 和 tomcat 等这些服务器,可是总感觉还是不 ...

  3. 通过Application存取公共数据比如登录信息等..

    Android系统在运行每一个程序应用的时候,都会创建一个Application对象,用于存储与整个应用相关的公共变量.一个Android应用只会生成一个Application对象,在不同的Activ ...

  4. 基于Vue的WebApp项目开发(三)

    实现根组件通用的头部和底部样式 明白由webpack搭建起来的Vue项目的执行流程,那么就可以知道实现这个需要只要在根组件和入口文件上做“手脚”即可 <!--以后项目的根组件--> < ...

  5. 爬虫day03之scrapy安装与使用

    参考博客 技术问题不要问,业务问题可以问是不是有一种更好的方法? scrapy windows安装 1. 安装scrapy 参考博客 https://www.cnblogs.com/wupeiqi/a ...

  6. ubuntu下面解压tar.gz包报错:tar命令报错: gzip: stdin: not in gzip format tar: Child returned status 1 tar: Error

    原因: 压缩包文件不完整(损坏或者其他原因) 比如今天下载的tomcat8,使用ubuntu的命令下载的 curl -O http://apache.mirrors.ionfish.org/tomca ...

  7. Django基础之form操作

    Form表单的功能 自动生成HTML表单元素 检查表单数据的合法性 如果验证错误,重新显示表单(数据不会重置) 数据类型转换(字符类型的数据转换成相应的Python类型) Form相关的对象包括 Wi ...

  8. Docker的一些常用命令

    # systemctl start docker //启动docker # systemctl restart docker //重启docker # systemctl enable docker ...

  9. 自动化测试基础篇--Selenium unittest生成测试报告(HTMLTestRunner)

    如何生成HTMLTestRunner测试报告.接上篇文章,对于unittest框架,运行后,测试结果不便于查看,同时多个case存在的时候,可能会导致case result记录不正确的情况. 为此,引 ...

  10. Angular5中提取公共组件之checkbox list

    因为工作原因,需要使用到checkbox list多选项功能. 一直在尝试在checkbox组件中添加NgModel的属性,但是只能在单个checkbox复选框上使用,checkbox list就没办 ...