java-io的自己理解

刚开始学java的io流时,一直傻傻分不清楚,到底哪个时候使用inputStream,什么时候使用outputStream,这几天就抽了个时间好好琢磨了下。

之前自学时,看的视频,黑马的老师讲的是看程序本身,魔乐科技的老师讲的是操作对象,一直觉得讲的不够细致,自己慢慢地查找各位大佬的博客,总结出一条好理解的说法。

看内存,为什么看操作的对象是内存呢,因为程序是跑在内存中的。只有理解操作对象是内存后,两位老师的讲解才说得通了。当程序需要将字符串输入到磁盘的某个文件时,文件的传输方向是 内存 --> 磁盘。下面列个代码大家理解下

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

public class TestOutputStreamDemo {
	public static void main(String[] args) throws Exception {
		//1.根据文件路径  创建File对象
		File file = new File("E:"+File.separator+"hello.txt");
		//安全起见   ----    避免异常
		if(!file.getParentFile().exists()) {//必须保证父目录的存在
			file.getParentFile().mkdirs();//不存在  则创建父目录
		}
		//2.根据字节流或字符流的子类  实例化父类对象     意味着只能进行文件处理
		//OutputStream os = new FileOutputStream(file);//文件内容的覆盖
			//如果需要进行文件内容的追加,不是覆盖
		OutputStream os = new FileOutputStream(file,true);//文件内容的追加
		//3.数据的读写操作   这里是向文件中  写数据
		//String msg = "hello java";
			//如果需要对文件进行加入并换行操作    单独的 \n不会去进行换行操作
		String msg = "hello.java\r\n";
		//msg.getBytes()  只是说明是内存中的数据信息   需要将内存中的数据信息写入到磁盘中去所以使用的是out
		os.write(msg.getBytes());
		//4.关闭流   避免资源的消耗
		os.close();
		
	}
}

这里使用的是outputStream下的子类   文件输出流(操作的是文件!)

当我们需要将磁盘中的某个文件读取到内存中时,此时的流的方向是    磁盘--->内存   所以使用inputStream这个抽象类,还是举个代码例子说明下。

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;

public class TestInputStreamDemo {
	public static void main(String[] args) throws Exception {
		File file = new File("E:"+File.separator+"hello.txt"); 
		System.out.println(file.getName());
		if(file.exists()) {//必须保证文件本身存在
			FileInputStream fileInputStream = new FileInputStream(file);
			byte[] data = new byte[1024];//吃饭用的勺子   -----  每次可以读取到的最大数量
			//1.一满勺,刚好装够最大数据,这时read返回的长度为定义的容器大小
			//2.不够一勺,返回能够读取到的字节的长度
			//3.没有了,返回-1
			int len = fileInputStream.read(data);//此时的数据读取到了数组中
			System.out.println(len);
			//输出的数组中所有的内容(数组中总长度1024  装不完   导致数据打印有"      ")
			//System.out.println("读取内容【"+new String(data)+"】");
			System.out.println("读取内容【"+new String(data,0,len)+"】");
			fileInputStream.close();
		}
	}
}

上面的注释很好理解啦  哈哈,我喜欢将代码结合现实生活来看问题。

上面的两个代码段已经很好说明问题了,相信和我一样纠结不知道怎么用io的小伙伴,对输入输出流有了个好的理解了吧,下面再说一个输入流和输出流结合使用,拷贝文件的代码,一个是一个字节一个字节读再写的操作,一个是刚开始创建一个集装箱,装满一定数量的数据后再写的操作,大家可以尝试运行下看时间比,不多说,先上代码

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

/**
 * 大文件的拷贝  两种方式时间对比
 * 
 * @author 76519
 *
 */
public class TestDemo {
	public static void main(String[] args) {
		// 创建两个独立的线程 分别测试
		new Thread(() -> {
			String path1 = "E:" + File.separator + "download" + File.separator + "SecureCRT_6.5.3.490_XiaZaiBa.exe";
			String path2 = "E:" + File.separator + "wanwan" + File.separator + "demo1" + File.separator
					+ "SecureCRT_6.5.3.490_XiaZaiBa.exe";
			try {
				copyOne(path1, path2);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}).start();
		
		new Thread(() -> {
			String path1 = "E:" + File.separator + "download" + File.separator + "SecureCRT_6.5.3.490_XiaZaiBa.exe";
			String path2 = "E:" + File.separator + "wanwan" + File.separator + "demo2" + File.separator
					+ "SecureCRT_6.5.3.490_XiaZaiBa.exe";
			try {
				copyTwo(path1, path2);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}).start();
	}

	/**
	 * 文件拷贝方式一
	 * 
	 * @param onePath
	 * @param twoPath
	 * @throws Exception
	 */
	public static void copyOne(String onePath, String twoPath) throws Exception {
		File fileOne = new File(onePath);
		File fileTwo = new File(twoPath);
		if (!fileOne.getParentFile().exists()) {
			fileOne.getParentFile().mkdirs();
		}
		if (!fileTwo.getParentFile().exists()) {
			fileTwo.getParentFile().mkdirs();
		}
		// 首先需要将磁盘中某个文件内容读取到内存中
		InputStream inputStream = new FileInputStream(fileOne);
		// 读取到的文件资源 写入到新的磁盘的某个文件中
		OutputStream outputStream = new FileOutputStream(fileTwo);
		// 方式一的读取
		long startTime = System.currentTimeMillis();
		// 每次读取一个字节的文件
		int len = 0;
		while ((len = inputStream.read()) != -1) {
			// 将读取到的 一个字节文件 从内存中 放入磁盘中
			outputStream.write(len);
		}
		long endTime = System.currentTimeMillis();
		System.out.println("方式一总共花费时间:" + (endTime - startTime));
		inputStream.close();
		outputStream.close();
	}

	/**
	 * 文件拷贝方式二
	 * 
	 * @param onePath
	 * @param twoPath
	 * @throws Exception
	 */
	public static void copyTwo(String onePath, String twoPath) throws Exception {
		File fileOne = new File(onePath);
		File fileTwo = new File(twoPath);
		if (!fileOne.getParentFile().exists()) {
			fileOne.getParentFile().mkdirs();
		}
		if (!fileTwo.getParentFile().exists()) {
			fileTwo.getParentFile().mkdirs();
		}
		// 首先需要将磁盘中某个文件内容读取到内存中
		InputStream inputStream = new FileInputStream(fileOne);
		// 读取到的文件资源 写入到新的磁盘的某个文件中
		OutputStream outputStream = new FileOutputStream(fileTwo);
		// 方式一的读取
		long startTime = System.currentTimeMillis();
		// 创建一片独立的载体 每次多读取指定长度的数据 存在车厢里运输
		byte[] bytes = new byte[1024];
		// 每次读取一个字节的文件
		int len = 0;
		while ((len = inputStream.read(bytes)) != -1) {
			// 将读取到的 一个字节文件 从内存中 放入磁盘中
			outputStream.write(bytes, 0, len);
		}
		long endTime = System.currentTimeMillis();
		// new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS").format(new Date(endTime -
		// startTime))
		System.out.println("方式二总共花费时间:" + (endTime - startTime));
		inputStream.close();
		outputStream.close();
	}
}

我随便找的一个exe文件,java的这个拷贝代码可以拷贝任意格式的文件。

为什么创建两个线程,是不想再main主线程中做一个耗时的操作,造成显示和两个代码运行的影响。java8新特性,lamada表达式。

运行结果

方式二总共花费时间:51
方式一总共花费时间:31053

为什么时间差上面会有如此大的差距呢,举个栗子,就好比你吃饭,是一勺子一勺子吃快点还是一粒米一粒米吃快点。

扫描二维码关注公众号,回复: 2915074 查看本文章

代码方式二中,添加一个byte[] bytes = new byte[1024];然后再while循环中(len = inputStream.read(bytes),这里不是读数组(我以前学的不好,老是理解为读数组),这个操作叫做读取数据放入数组中暂存。

就先说到这里啦,有问题还望各位大佬指出,小白不胜感激!

猜你喜欢

转载自blog.csdn.net/qq_38322527/article/details/81705225