JavaSE-IO流

1.IO流

        1.1 概述

         流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象。即数据在两设备间的传输称为流,流的本质是数据传输,根据数据传输特性将流抽象为各种类,方便更直观的进行数据操作。          I : Input输入       O : output输出

         1.2 分类

         按处理数据类型不同,分为字节流和字符流

         按数据流向的不同,分为输入流和输出流。(入和出是相对于内存来讲的)

         按功能不同,分为节点流(直接操作数据源)和处理流(对其它流进行处理)

         1.3 四大抽象类

         字节流

                 输入流:InputStream

                 输出流:OutputStream

        字符流

                 输入流:Reader

                 输出流:Writer

         1.4 文件流

                 1.4.1 FileInputStream
                 1.4.1.1 概述

                         以字节的方式进行文件中的内容的读取操作,要想读取文件需要先找到文件的位置,文件位置可以通过绝对路径或相对路径找到。

 绝对路径 : 绝对路径是从系统的根目录开始,一级一级指向目标文件或资源的完整路径.

                  例如:D:/eclipse/workspace/day19_0120/src/day19_12/Cow.java*

相对路径 : 相对路径是以当前文件或目录为基准,指向目标文件或资源的简化路径.

                 例如:../day19_0120/src/day19_12/Cow.java

                 注:./ 为当前目录, ../ 为上级目录, ../../ 为上上级目录,依次类推,在eclipse中./定位到当前目录。

                 1.4.1.2 常用方法

                read()方法: 从输入流中读取一个字节,返回一个int值,如果到达流的末尾,返回-1。

                read(byte[] b)方法: 从输入流中读取一定数量的字节,并将其存储在字节数组b中,返回实际读取的字节数,如果到达流的末尾,返回-1。

                read(byte[] b, int off, int len)方法:从输入流中读取最多len个字节,并将其存储在字节数组b中,从偏移量off开始,返回实际读取的字节数,如果到达流的末尾,返回-1。

                available()方法:返回从输入流中可以读取的字节数目。

                skip(long n)方法:跳过并丢弃输入流中的n个字节。

                close()方法:关闭输入流,释放与之关联的资源。

        问:为什么read方法返回的是int类型,而不是byte类型?

        因为字节流可以操作任意类型的文件,这些文件在底层都是以二进制存储的,一个字节是八位二进制,也就是说我如果返回类型为byte类型,是有可能在读取的过程中出现连续的八个1,而11111111是byte类型的-1,我们的程序在读到-1时,就不会再往下执行,导致文件没有读完。所以再读取的时候采用int类型的接受,每次读取一个字节都会补0凑足32位,一旦遇到11111111就会在前面补24个0,那么byte类型的-1就变成了int类型的255,就可以保证整个数据读完,而结尾的-1就是int类型的-1,用来判断流的结尾。

                 1.4.1.3 Read使用
public static void main(String[] args) {
		FileInputStream file = null;
		try {
			// 打开对应文件数据
			file = new FileInputStream("../day19_0120/src/day19_12/Cow.java");
			// read:读取文件中的一个字节,返回当前字节对应的ASCII码值(int),并指向下一个字节
			// 到达文件末尾没有数据返回-1
			System.out.println((char)file.read());
			System.out.println((char)file.read());
			System.out.println((char)file.read());
			System.out.println((char)file.read());
			System.out.println((char)file.read());
			System.out.println((char)file.read());
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			// 关闭资源
			if(file != null) {
				try {
					file.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			
		}
		
	}
public static void main(String[] args) {
		// 从java7开始,支持自动关闭资源
		try(FileInputStream file = new FileInputStream(
				"../day19_0120/src/day19_12/Cow.java")){
			int temp = 0;
			while((temp = file.read()) != -1) {
				System.out.print((char)file.read());
			}
		}catch(Exception e) {
			e.printStackTrace();
		}
	}
                 1.4.1.4 Read重载使用
// Read 重载使用
public class IO_FileInputStream_02 {
	public static void main(String[] args) {
		// 从java7开始,支持自动关闭资源
		try (FileInputStream file = new FileInputStream("../day19_0120/src/day19_12/Cow.java")) {
			// read方法重载,可以传入byte数组,用来提高读取效率,一次读取一个数组
			// 返回当前次,读取的个数(这一次读取了几个字节),到达文件末尾返回-1
			// avaliable():获取和读取的字节数
			System.out.println(file.available());
			// byte[] bytes = new byte[file.available()];
			byte[] bytes = new byte[1024];
			int temp = 0;
			while ((temp = file.read(bytes)) != -1) {
				System.out.print(new String(bytes,0,temp));
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
         1.4.2 FileReader
                 1.4.2.1 概述

                 字符输入流一般适用于纯文本文件,用来解决读取文字乱码问题,像压缩包,视频,图片等都使用字节流而不是字符流。

                 read():一次读取一个字符,返回对应的ASCII码,到达文件末尾返回-1

                 read(char[]):一次读取一个字符数组,返回本次读取的个数

public class IO_FileInputStream_03 {
	public static void main(String[] args) {
		try (FileReader file = new FileReader("../day19_0120/src/day19_12/Cow.java")) {
			// 创建字符数组
			char[] chars = new char[1024];
			int temp = 0;
			// 传入字符数组读取
			while ((temp = file.read(chars)) != -1) {
				System.out.print(new String(chars,0,temp));
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
          1.4.3 FileOutputStream
                 1.4.3.1 概述

                 字节输出流,用于将文件中的数据写出到硬盘里, 如果文件不存在就会自动创建,但是不会创建目录,如果目录不存在就会报错。构造方法可以传入两个参数,一个是文件所在的目录,一个是写出方式(true 表示追加写出,false表示覆盖写出)。如果构造方法只传入文件路径,默认是覆盖写出,覆盖写出会在创建输出流对象的时候,把该文件里的内容清空。

                 1.4.3.2 常用方法

                        write(int b)方法:将指定的字节写入此文件输出流。

                        write(byte[] b)方法:将指定字节数组中的所有字节写入此文件输出流。

                        write(byte[] b, int off, int len)方法:将指定字节数组中从偏移量off开始的len个字节写入此文件输出流。

                        close()方法:关闭此文件输出流并释放与此流关联的所有系统资源。

                        flush()方法:刷新此文件输出流并强制将所有缓冲的输出字节写入目标。

                 1.4.3.3 构造方法

                 1.4.3.4 使用方法
public static void main(String[] args) {
		try (	// true 追加写出
				// FileOutputStream fos = new FileOutputStream("./src/a.txt",true);
				// false 覆盖写出
				FileOutputStream fos1 = new FileOutputStream("./src/a.txt",false);
				){
			byte[] bytes = {97,98,99,100,101,102};
			// 写出字符数组中所有内容
			fos1.write(bytes);
			// 写出字符数组中0~3的内容
			fos1.write(bytes, 0, 3);
			// 写出int类型,数字会显示为对应的字符
			fos1.write(97);
			// 字符串不能直接写出,需要转换为字节数组
			fos1.write("你好。".getBytes());
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

                 1.4.4 FileWriter

public static void main(String[] args) {
		try (FileWriter fw = new FileWriter("./src/a.txt")){
			// 写出int
			fw.write(65);
			// 写出字符数组
			char[] c = {65,66,67,68,69};
			fw.write(c);
			fw.write(c,0,3);
			// 写出字符串
			fw.write("你好");
			// 写出字符串中特定个数的字符
			fw.write("你好吗",0,2);
			// 刷缓存
			fw.flush();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

 1.5 缓冲流

         字节流:

                 输入流:BufferedInputStream

                 输出流:BufferedOutputStrea

         字符流:

                 输入流:BufferedReader

                 输出流:BufferedWriter

         缓冲流的特点:

                 1.主要是为了提高效率二存在的,减少物理读取次数

                 2.提供readLine(),newLine()这样的便捷方法(针对字符缓冲流)

                 3.在读取和写入时,会有缓存部分,调用fluse为刷新缓存,将数据写入硬盘

        1.5.1 BufferedReader

// BufferedReader
// 节点流的构造方法传入的是文件路径
// 处理流的构造方法传入的是节点流对象
// 只要处理流关闭,节点流也会关闭
public class IO_BufferedReader_00 {
	public static void main(String[] args) {
				// 创建字符输入流
		try(FileReader fr = new FileReader("./src/a.txt");
				// 创建字符输入缓冲流,传入字符流
			BufferedReader br = new BufferedReader(fr);
				) {
			// readLine()读取一行字符串,到达文件末尾返回null
			String temp = null;
			while ((temp = br.readLine()) != null) {
				System.out.println(temp);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
        1.5.2 BufferedWriter
//BufferedWriter
public class IO_BufferedWriter_00 {
	public static void main(String[] args) {
		try (	// 创建字符输出流
				FileWriter fw = new FileWriter("./src/a.txt");
				// 创建字节输出缓冲流,传入字符输出流
				BufferedWriter bw = new BufferedWriter(fw);
				){
			// 输出字符串
			bw.write("字符输出缓冲流");
			// 输出整数,会显示为对应的字符
			bw.write(99);
			// 输出字符数组
			char[] chars = {48,49,50,51};
			bw.write(chars);
			
			// 新增换行方法
			bw.newLine();
			bw.write("换行");
			
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

 1.6 转换流

         输入流:InputStreamReader

         输出流:OutputStreamWriter

         转换流特点:

                 1. 转换流是指将字节流像字符流的转换,主要有InputStreamReader和OutputStreamWriter

                 2. InputStreamReader:将字节输入流转换为字符输入流

                 3. OutputStreamWriter:将字节输出流转换为字符输出流

        1.6.1 使用方式
//InputStreamReader
public class IO_InputStreamReader {
	public static void main(String[] args) {
		try (	// 字节输入流
				FileInputStream fis = new FileInputStream("./src/a.txt");
				// 转换为字符流
				InputStreamReader isr = new InputStreamReader(fis);
				// 字符输入缓冲流
				BufferedReader br = new BufferedReader(isr);
				){
				System.out.println(br.readLine());
			
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
// 解决乱码问题
// 如果文件编码方式与开发环境使用的编码方式不同,读取时会出现乱码问题
// 在不改变开发环境使用的编码方式和文件原来的编码方式的情况下,可以将字节流转换为字符流时指定与文件对应的编码格式

public class IO_InputStreamReader_00 {
	public static void main(String[] args) {
		try ( // 字节输入流,文件a.txt使用的时GBK编码,开发环境使用的时UTF-8编码
				FileInputStream fis = new FileInputStream("D:/a.txt");
				// 转换为字符流,指定编码格式为GBK,防止出现乱码
				InputStreamReader isr = new InputStreamReader(fis,"GBK");
				// 字符输入缓冲流
				BufferedReader br = new BufferedReader(isr);) {
			System.out.println(br.readLine());

		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

 1.7 打印流

         特点:

                1.打印流是输出最方便的类,包含字节打印流PrintStream和字符打印流PrintWriter

                2.PrintStream是OutputStream的子类,把一个输出流的实例传递到打印流之后,可以更加方便的,输出内容,相当于重新包装了一边输出流        

                3.PrintStream类的print()方法被重载很多次,print(int i),print(boolean i)等。

         标准输入输出:

                 java的标准输入/输出分别通过System.in和System.out来代表,在默认情况下分别代表键盘和显示器,当程序通过System.in获取输入时,实际上是通过键盘获取输入, 当程序通过System.out获取输出时,实际上是通过显示器获取输出。

         在System类中提供三个重定向标准输入/输出的方法

                 1.static void setErr(PrintStream err) 重定向标准输出错误流

                 2.static void setIn(InputStream in) 重定向标准输入流

                 3.static void setOut(PrintStream out) 重定向标准输出流

         1.7.2 使用方式
public static void main(String[] args) {
		try(FileOutputStream fos = new FileOutputStream("./src/a.txt");
				PrintStream ps = new PrintStream(fos);
				) {
			// 打印流中提供了很多print方法,可以更加方便的打印各种类型
			ps.print(false);
			ps.print(48);
			ps.print("啦啦啦");
			ps.print(32.34);
			
			// 平常用的打印语句就是这个打印流,只不过System中有三个标准流
			// in 标准输入(控制台) out 标准输出(控制台) err 标准错误打印
			System.out.println(123);
			
			// 使用重定向方法,可以指定System中打印流的输出对象
			System.setOut(ps); // 指定输出到./src/a.txt
			System.out.println(12345);
			System.out.println("你好");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

        1.8 数据流

                1.8.1 概述

                 数据流: 为了方便操作java中的基本数据类型和字符串类型数据,可以使用数据流来进行操作,数据流以二进制形式进行数据传递,并且读写顺序和类型必须一致,常用来网络数据传输。

// 写入
public class IO_DataOutputStream {
	public static void main(String[] args) {
		try (	
				FileOutputStream fos = new FileOutputStream("./src/test");
				DataOutputStream dos = new DataOutputStream(fos);
				){
			// 可写入多种类型
			dos.writeInt(12);
			dos.writeByte(2);
			dos.writeLong(123456);
			dos.writeShort(122);
			dos.writeUTF("写入");
			dos.writeDouble(12.4);
			
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
// 读取
public class IO_DataInputStream {
	public static void main(String[] args) {
		try(
				FileInputStream fis = new FileInputStream("./src/test");
				DataInputStream dis = new DataInputStream(fis);
				) {
			
			// 读取顺序需和写入的顺序和类型一致
			System.out.println(dis.readInt());
			System.out.println(dis.readByte());
			System.out.println(dis.readLong());
			System.out.println(dis.readShort());
			System.out.println(dis.readUTF());
			System.out.println(dis.readBoolean());
			
		} catch (Exception e) {
			e.printStackTrace();
		}
				
	}
}

        1.9 对象流

                1.9.1 概述

                 创建对象方式:1. new 2.反射机制 3.clone 4.反序列化

                 序列化: 把堆内存对象进行持久化,保存到硬盘里

                 反序列化: 把硬盘中的对象,载入到内存中

                 1.9.2 注意

                 要序列化的类必须实现Serializable接口,否则会报错

                 1.9.3 序列化
// 要序列化的实体类
public class User implements Serializable{
	private String name;
	// transient 修饰符,修饰的属性不能被序列化
	transient int age;
	// serialVersionUID 简单来说就是class的版本控制
	// 每次修改class时,UID都会自动进行修改,导致反序列化出的对象不能使用修改后的变量或方法,
	// 所以一般我们会手动设置一个固定的UID值
	private static final long serialVersionUID = 1L;
	
	@Override
	public String toString() {
		return "User [name=" + name + ", age=" + age + "]";
	}
	public User() {
		super();
	}
	public User(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	
}
public class ObjectOutputStream_00 {
	public static void main(String[] args) {
		User user = new User("张三",19);
		try (
				FileOutputStream fos = new FileOutputStream("./src/day21_0123/temp");
				ObjectOutputStream oos = new ObjectOutputStream(fos);
				){
			// 将对象写入
			oos.writeObject(user);
			// 刷新缓存
			oos.flush();
			
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
                 1.9.4 反序列化
// 反序列化
public class ObjectInputStream_00 {
	public static void main(String[] args) {
		try(	
				FileInputStream fis = new FileInputStream("./src/day21_0123/temp");
				ObjectInputStream ois = new ObjectInputStream(fis);
				) {
				User user = (User)ois.readObject();
				System.out.println(user);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
                 1.9.5 serialVersionUID
    // serialVersionUID 简单来说就是class的版本控制
	// 每次修改class时,UID都会自动进行修改,导致反序列化出的对象不能使用修改后的变量或方法,
	// 所以一般我们会手动设置一个固定的UID值
	private static final long serialVersionUID = 1L;
                 1.9.6 Transient
    // transient 修饰符,修饰的属性不能被序列化
	transient int age;

2. File类

        2.1 概述

                 File类提供了文件和目录相关的操作(增删改查)

                 File对象需要传入文件路径的,但是路径可以是不存在的

         2.2 构造方法

                 public File(String pathname)以pathname为路径创建Fiel对象,可以是绝对路径或相对路径, 如果pathname是相对路径,则默认的当前路径在系统属性user.dir中存储。

                 public File(String parent, String child)以parent为父路径,child为子路径创建File对象。

                 public File(File parent, String child) 根据一个父对象和子路径创建File对象。

         2.3 常用方法

         获取功能:

                 public String getAbsolutePath(): 获取绝对路径

                 public String getPath(): 获取路径

                 public String getName(): 获取名称

                 public String getParent(): 获取上级文件路径,若无,返回null

                 public long length() : 获取文件长度(即:字节数),不能获取目录的长度

                 public long lastModified() : 获取最后一次的修改时间

                 public String[] list() : 获取指定目录下所有文件或者文件目录的名称数组

                 public File[] listFiles() :获取指定目录下的所有文件或者文件目录的File数组

         重命名功能:

                public boolean renameTo(File dest):把文件重命名为指定的文件路径

        判断功能:

                public boolean isDirectory():判断是否是文件目录

                public boolean isFile() :判断是否是文件

                public boolean exists() :判断是否存在

                public boolean canRead() :判断是否可读

                public boolean canWrite() :判断是否可写

                public boolean isHidden() :判断是否隐藏

        创建删除功能:

                public boolean createNewFile() :创建文件。若文件存在,则不创建,返回false

                public boolean mkdir() :创建文件目录。如果此文件目录存在,就不创建了。 如果此文件目录的上层目录不存在,也不创建。

                public boolean mkdirs() :创建文件目录。如果上层文件目录不存在,一并创建

                注意事项:如果你创建文件或者文件目录没有写盘符路径,那么,默认在项目 路径下。

                public boolean delete():删除文件或者文件夹

                删除注意事项:

                Java中的删除不走回收站。

                要删除一个文件目录,请注意该文件目录内不能包含文件或者文件目录

         2.4 使用方式

public static void main(String[] args) throws Exception {
		// 创建文件对象
		File file = new File("E:/com/test");
		// 获取全路径
		System.out.println(file.getAbsolutePath());
		// 获取文件名
		System.out.println(file.getName());
		// 根据不同操作系统,调整分隔符,windows系统是\ Linux是/
		System.out.println(File.separator);
		// 获取父路径,返回值为字符串
		System.out.println(file.getParent());
		// 获取父路径文件对象
		File supFile = file.getParentFile();
		// 判断是否为文件
		System.out.println(file.isFile());
		// 判断是否为目录
		System.out.println(file.isDirectory());
		// 获取最后一次修改时间,返回毫秒数
		System.out.println(file.lastModified());
		// 判断是否存在
		System.out.println(file.exists());
		// 创建对应文件,但是不会创建文件夹
		// 如果该文件已经存在,就不在创建,返回false,否则返回true 
		System.out.println(file.createNewFile());
		// 删除,删除成功返回true
		file.delete();
		// 执行结束后,JVM退出时,删除
		file.deleteOnExit();
		// 创建文件夹
		file = new File("E:/com/test/a/b/c/test.txt");
		supFile = file.getParentFile();
		if(!supFile.exists()) {
			// 创建文件夹路径,只能创建c,如果a,b不存在会报错
			supFile.mkdir();
			// 递归创建所有文件夹
			supFile.mkdirs();
		}
		file.createNewFile();
		
		// 获取所有文件对象
		File[] files = file.listFiles();
		for (File file2 : files) {
			System.out.println(file2.getAbsolutePath());
		}
	}

         2.5 递归复制

                文件夹复制

                1 文件复制,本质就是输入和输出 , 先完成单个文件复制的方法

                2 获取该目录下所有子文件

                3 接收文件对象

                4 判断该文件对象是否是文件,如果是,调用单个文件复制方法,终止

                5 如果是目录,则获取该目录下所有子文件,然后遍历所有子文件,依次递归传入该方法

                6 对所有文件对象进行以上相同操作

public class IO_Copy {
	public static void main(String[] args) {
		checkMenu(new File("D:/com/java"));
		System.err.println("复制成功");
	}
	
	public static void checkMenu(File file) {
		if(file.isFile()) {
			// 判断文件对象是否时文件,如果是就进行复制
			// 起始路径和目标路径不能相同,否则会导致文件清空
			// 获取文件路径
			String filePath = file.getAbsolutePath();
			// 目标路径
			String newFilePath = "F" + filePath.substring(1);
			// 获取目标路径的父目录对象
			File supFile = new File(newFilePath).getParentFile();
			// 判断目标目录是否存在
			if(!supFile.exists()) {
				supFile.mkdirs();
			}
			// 复制
			copyFile(filePath,newFilePath);
			return;
		}
		// 到这里说明是目录
		// 获取所有子文件并递归调用
		File[] files = file.listFiles();
		for (File file2 : files) {
			checkMenu(file2);
		}
	}
	
	// 文件复制方法
		public static void copyFile(String srcPath,String destPath) {
			try(	FileInputStream input = new FileInputStream(srcPath);
					BufferedInputStream in = new BufferedInputStream(input);
					FileOutputStream output = new FileOutputStream(destPath);
					BufferedOutputStream out = new BufferedOutputStream(output);
					) {
				byte[] bytes = new byte[10240];
				int temp = 0;
				while((temp = in.read(bytes)) != -1) {
					out.write(bytes, 0, temp);
				}
				out.flush();
				
			} catch (Exception e) {
				e.printStackTrace();
			} 
		}
}

你可能感兴趣的:(java,开发语言,eclipse)