zoukankan      html  css  js  c++  java
  • Java基础教程——字节流

    IO流

    水流 特点
    连续性 逝者如斯夫,不舍昼夜;
    方向性 一江春水向东流。水往低处流。百川东到海,何时复西归?少壮不努力,老大徒伤悲!
    源头尽头 唯有源头活水来;覆水难收

    Java里的IO也有这样的特点。

    IO:数据从硬盘流向内存(Input),或者从内存流向硬盘(Output)。

    IO流分类:

    按照流的流向来分:输入流、输出流。
    |-输入流:读入内存。
    |-输出流:写出到硬盘等设备。

    按操作数据单元分:字节流、字符流
    |-字节流:8位
    |-字符流:16位

    按流的角色分:节点流、处理流。
    |-节点流:特定的IO设备(如硬盘),也叫低级流
    |-处理流:经过封装的流,也叫高级流、包装流,可以消除不同节点流的差异(典型的装饰器模式)

    Java的IO流有40多个类,高抽象层的基类有四个:

    字节流 字符流
    输入流 InputStream Reader
    输出流 OutputStream Writer

    字节流

    字节流:100100011010100010

    可以操作所有文件,包括文本文件、视频、音频、压缩文件等等都可以用字节流读写。
    

    两个重要的抽象类:

    (1)抽象类 java.io.OutputStream,是输出字节流的所有类的超类

    |--API方法摘要:
    |--|--void write(byte[] b) 将 b.length 个字节从指定的 byte 数组写入此输出流。
    |--|--abstract void write(int b) 将指定的字节写入此输出流。
    |--|--void close() 关闭此输出流并释放与此流有关的所有系统资源。

    (2)抽象类 java.io.InputStream,是输入字节流的所有类的超类

    |--API方法摘要:
    |--|--abstract int read()从输入流中读取数据的下一个字节。
    |--|--int read(byte[] b) 从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中。
    |--|--void close() 关闭此输入流并释放与该流关联的所有系统资源。

    FileOutputStream写文件

    // 文件输出流。完整地说,是文件字节输出流。
    public class FileOutputStream extends OutputStream
    

    步骤:
    1.创建流对象
    2.调用write方法,把数据写入文件
    3.释放资源

    import java.io.*;
    public class 文件字节输出流 {
    	public static void main(String[] args) {
    		File file = new File("文件字节输出流.txt"); // 创建文件对象
    		try {
    			// (1)构造:通过文件对象创建文件输出流对象
    			FileOutputStream fos = new FileOutputStream(file);
    			// (2)写入文件
    			// (2.1)write(int b) 将"单个字节"写入到文件中
    			for (int i = 49; i < 97; i++) {
    				fos.write(i);
    				fos.write(' ');
    			}
    			// (2.2)write(byte[] b) 将"字节数组"中的数据全部写入文件
    			byte[] buffer = "I Love Java,你呢?".getBytes();
    			fos.write(buffer);
    			// (3)关闭流
    			fos.close();
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    	}
    }
    

    追加:

    使用构造方法:FileOutputStream(File file, boolean append)

    			// 构造:通过文件对象创建文件输出流对象
    			// 附加第二个参数true,指定进行文件追加,默认为不追加
    			fos = new FileOutputStream(file, true);
    

    回车换行:

    CR(carriage return),回车,
    LF(line feed),换行,

    windows:
    linux或unix:
    mac:

    FileInputStream读文件

    public class FileInputStream extends InputStream
    
    import java.io.*;
    public class 文件字节输入流 {
    	static final int C_CONDITION = 2;
    	public static void main(String[] args) {
    		try {
    			File file = new File("testRead.dat"); // 创建文件对象
    			// 【1】创建输入流对象,相当于打开文件
    			FileInputStream fis = new FileInputStream(file);
    			if (C_CONDITION == 1) {
    				// 【2】.read():读取单个字节
    				for (int i = 0; i < file.length(); i++) {
    					// 循环读取"字节",转为字符输出,英文没问题
    					int read = fis.read();
    					char ch = (char) read;
    					System.out.print(ch);
    				}
    				System.out.println();
    			} else {
    				// 【2】.read(byte[] b):读取文件中的数据到字节数组
    				// 根据文件的字节长度创建字节数组
    				long len = file.length();
    				byte[] buf = new byte[(int) len];
    				fis.read(buf);
    				// 利用字节数组创建字符串
    				String str = new String(buf);
    				System.out.println(str);
    			}
    			// 【3】关闭流
    			fis.close();
    		} catch (FileNotFoundException fnfe) {
    			System.out.println("文件打开失败。");
    		} catch (IOException ioe) {
    			ioe.printStackTrace();
    		}
    	}
    }
    

    复制文件

    package ahjava.io;
    import java.io.*;
    public class 复制文件 {
    	public static void main(String[] args) {
    		字节流复制文件();
    	}
    	static void 字节流复制文件() {
    		File srcFile = new File("testRead.dat"); // 源文件对象
    		File destFile = new File("testCopy.java"); // 目标文件对象
    		if (destFile.exists()) {
    			// 判断目标文件是否存在,存在则删除
    			destFile.delete();
    		}
    		// 目标文件不存在才复制
    		try {
    			destFile.createNewFile();
    			// 创建文件输入/输出流对象
    			FileInputStream fis = new FileInputStream(srcFile);
    			FileOutputStream fos = new FileOutputStream(destFile);
    			// 创建字节数组,作为临时缓冲
    			byte[] buf = new byte[128];
    			System.out.println("开始复制文件...");
    			int len = -1;
    			// 循环从文件输入流中读取数据
    			while ((len = fis.read(buf)) != -1) {
    				System.out.println(len);
    				// 写入到文件输出流中
    				fos.write(buf, 0, len);
    			}
    			System.out.println("文件复制成功!");
    			fis.close(); // 关闭流
    			fos.close();
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    	}
    }
    

    上面的代码有哪些风险?

    改进版:

    	static void 字节流复制文件2() {
    		// 1.close()提取到finally中
    		// 2.提取FilexxxStream对象
    		// 3.初始化(否则不准close)
    		// 4.close()时加判空语句
    		FileInputStream fis = null;
    		FileOutputStream fos = null;
    		File srcFile = new File("testRead.dat"); // 源文件对象
    		File destFile = new File("testCopy.java"); // 目标文件对象
    		if (destFile.exists()) {
    			// 判断目标文件是否存在,存在则删除
    			destFile.delete();
    		}
    		// 目标文件不存在才复制
    		try {
    			destFile.createNewFile();
    			fis = new FileInputStream(srcFile);
    			fos = new FileOutputStream(destFile);
    			// 创建字节数组,作为临时缓冲
    			byte[] buf = new byte[128];
    			System.out.println("开始复制文件...");
    			int len = -1;
    			// 循环从文件输入流中读取数据
    			while ((len = fis.read(buf)) != -1) {
    				System.out.println(len);
    				// 写入到文件输出流中
    				fos.write(buf, 0, len);
    			}
    			System.out.println("文件复制成功!");
    			// 关闭流
    		} catch (IOException e) {
    			e.printStackTrace();
    		} finally {
    			if (fis != null) {
    				try {
    					fis.close();
    				} catch (IOException e) {
    					// TODO Auto-generated catch block
    					e.printStackTrace();
    				}
    				fis = null;
    			}
    			if (fos != null) {
    				try {
    					fos.close();
    				} catch (IOException e) {
    					// TODO Auto-generated catch block
    					e.printStackTrace();
    				}
    				fos = null;
    			}
    		}
    	}
    

    又臭又长!

    Java 7异常处理写法:

    try后面增加括号,其中定义流对象,该流对象仅在try中有效,执行完毕自动释放,不需要写finally。

    try(流对象){
    } catch (IOException e) {
    }
    

    具体代码如下:

    	static void 字节流复制文件3() {
    		File srcFile = new File("testRead.dat"); // 源文件对象
    		File destFile = new File("testCopy.java"); // 目标文件对象
    		if (destFile.exists()) {
    			// 判断目标文件是否存在,存在则删除
    			destFile.delete();
    		}
    		// try(流对象)
    		try (FileInputStream fis = new FileInputStream(srcFile);
    				FileOutputStream fos = new FileOutputStream(destFile)) {
    			destFile.createNewFile();
    			// 创建字节数组,作为临时缓冲
    			byte[] buf = new byte[128];
    			System.out.println("开始复制文件...");
    			int len = -1;
    			// 循环从文件输入流中读取数据
    			while ((len = fis.read(buf)) != -1) {
    				System.out.println(len);
    				// 写入到文件输出流中
    				fos.write(buf, 0, len);
    			}
    			System.out.println("文件复制成功!");
    			// 关闭流
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    	}
    

    *Java9异常处理写法

    觉得try里的代码太繁琐,try()中可以引入外部的变量:

    FileInputStream	fis = new FileInputStream(srcFile);
    FileOutputStream fos = new FileOutputStream(destFile);
    try  (fis;fos){...}
    // ↑ 理想状态,代码并不能这么写
    

    然而,fis、fos本身需要抛异常,如果直接try...catch,这两个变量会变成另外的try中的局部变量;
    如果把声明提取到try之外,try (fis;fos)又需要变量是final的

    		FileInputStream fis = null;
    		FileOutputStream fos = null;
    		try {
    			fis = new FileInputStream(srcFile);
    			fos = new FileOutputStream(destFile);
    		} catch (FileNotFoundException e1) {
    			e1.printStackTrace();
    		}
    		try  (fis;fos) {
    

    CopyFile.java:20: 错误: 用作 try-with-resources 资源的变量 fis 既不是最终变量, 也不是实际上的最终变量
    try (fis;fos) {
    ^
    CopyFile.java:20: 错误: 用作 try-with-resources 资源的变量 fos 既不是最终变量, 也不是实际上的最终变量
    try (fis;fos) {

    所以,fis和fos需要往外抛出异常,外部调用的地方又需要捕获异常。比不用此功能还要麻烦。可运行代码如下:

    import java.io.*;
    public class CopyFile{
    	public static void main(String[] args) {
    		try {
    			copyJDK9();
    		} catch (FileNotFoundException e) {
    			e.printStackTrace();
    		}
    	}
    	static void copyJDK9() throws FileNotFoundException {
    		File srcFile = new File("testRead.dat");
    		File destFile = new File("testCopy.java");
    		if (destFile.exists()) {
    			destFile.delete();
    		}
    
    		FileInputStream	fis = new FileInputStream(srcFile);
    		FileOutputStream fos = new FileOutputStream(destFile);
    		try  (fis;fos) {
    			destFile.createNewFile();
    			byte[] buf = new byte[128];
    			System.out.println("start copy...");
    			int len = -1;
    			while ((len = fis.read(buf)) != -1) {
    				System.out.println(len);
    				fos.write(buf, 0, len);
    			}
    			System.out.println("success");
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    	}
    }
    
  • 相关阅读:
    WCF添加服务失败。服务元数据可能无法访问。请确保服务正在运行并且正在公开元数据。
    【C#】 实现WinForm中只能启动一个实例
    centos7防火墙问题
    ftp搭建记录
    centos7常用命令
    RocketMQ部署
    mongedb主从
    redis 主从复制+读写分离+哨兵
    keepalive+nginx
    分布架构分析
  • 原文地址:https://www.cnblogs.com/tigerlion/p/11179223.html
Copyright © 2011-2022 走看看