栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Day014--java中的I/O流

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Day014--java中的I/O流

java的输入输出流功能来自java.io包中的InputStream类(字节输入流),OutputStream类(字节输出流), Reader类(字符输入流),Writer类(字符输入流),这些类以流的形式处理数据【注释:流是一组有序的数据序列】。从上面我们可以看到不管是字节流还是字符流,都是有输入和输出流的,那么它们到底是什么呢?有人说输入流和输出流的流向问题很容易搞混,其实只要我们用自己的方法去记忆了,就不会有记不住的问题。学习不是任务,我们可以将它发展成我们的一种兴趣爱好,再接着发展成我们的特长。

输入输出流就好比我们渴了,想要喝水,就去找有饮水机的地方将水打到我们的杯子里面亦或者是自己的杯子里面有水就可以直接去喝。【注释:在这个案例里面我们是主体,水是流向我们(进入嘴巴再进入肚子)的,因此只要是流向我们的数据都要经过输入流的处理】。但是,等我们喝到一半了却看到里面有小强,还是什么的某种不明生物的遗体,就‘哇’的将水吐了出来,这里就体现了输出流,水从我们的嘴巴中吐出来(或者是喝坏肚子了从肛门出来)的,水流出我们的身体外面,因此就为输出流。

在计算机中程序从输入流读取数据,向输出流写入数据。I/O的基本模式如下:

  • 输入模式:由程序打开文件/网络/压缩包/其他数据源,获取指定的消息来源的数据流。
  • 输出模式:由程序向外输出读取到的数据源的内容,或者是由程序创建某个输出对象的数据源,将我们的数据写入到数据流中。我们的输出模式和输入模式的输入目标一样,都是文件/网络/压缩包/其他数据源(自己创建的)。
一,目录(文件)的创建

我们在进行 IO流之前需要指定我们的数据/文件保存的地方(目录),有些是不需要我们去手动创建的,直接将我们的数据文件保存进去即可,而有些时候我们需要手动的去创建目录,用于保存后期IO流处理时的数据文件【注释:在java中目录被当成文件来进行处理】

我们先来一起学习怎么创建目录

1,目录创建

 在java中提供了File类来让我们创建目录对象(new File),及其下的各种方法来对目录进行处理

  • 创建一级目录:mkdir()
  • 判断文件是否存在:exists()
  • 创建多级目录:mkdirs()
  • 删除空目录或文件:delete()
  • 获取文件名:getName()
  • 获取绝对路径:getAbsolutePath()
  • 得到文件父目录:getParent()
  • 得到文件大小(字节数):length()
  • 判断是否为目录:isDirectory()
  • 判断是否为文件:isFile()

 案例:判断我们的桌面上是否有该目录,没有的话创建,存在该目录之后获取该目录的目录名,获取绝对路径,得到目录的父目录,目录大小,及判断是否为目录,文件。

首先在我的桌面上是没有名为“工作目录”的目录,现在让我们去创建它。

  如下在我们的桌面上就会创建一个空的工作目录。

 接下来我们来获取该目录的相关信息

二, I/O流

上面的操作都是针对于目录的,那么我们的纯文件又该怎么去创建和操作呢?接下来让我们去认识I/O流。它将告诉我们该怎么去创建一个文件数据源。java中的流的分类有下面三种:

  • 按照数据的操作单位可以分为:字节流和字符流
  • 按照数据流的流向可分:输入流和输出流
  • 按照流的角色可以分为:节点流和处理流(包装流)
1,节点流

在节点流里面目前我们用得最多的就是文件流处理,因此我们先来认识文件流,在文件流里面又根据数据的操作单位分为字节流和字符流。

节点流:从一个特定的数据源读写数据(只能是指定的文件对象)有局限。

文件流-字节流

字节流:用于处理二进制文件,比方说音频,图片,压缩包等。

字节流中的输入流为FileInputStream,输出流为FileOutputStream。

FileInputStream类中我们常用的读取方法有以下两种:

  • read():一次读取单个字节,返回该字符的码值,如果读到文件末尾,就返回-1
  • read(byte[] b):一次读取多个字节,依旧读到文件末尾就返回-1【速度要快些】

FileOutputStream类中我们常用的读取方法有以下两种:

  • write():一次写入单个字节,无返回值
  • write(byte[] b):一次写入多个字节,依旧无返回值【速度要快些】

因为我们的I/O流操作默认是受检查异常,因此我们在对其操作时,必须进行异常捕获处理或者是声明抛出。

我们在读取文件时,可能存在文件不存在,文件路径错误,文件读取失败,文件关闭失败等异常,如果在发生异常时,想要知道发生的是什么异常,那么我们可以使用try-catch来进行捕获处理。

FileInputStream的使用案例:

我们读取桌面上的文件“MartinOdersky.txt”,并将结果输出到显示器

  接下来我们去一步一步的实现上面的效果:

如下在创建字节输入流对象时,显示爆红,并给我们提示,让我们抛异常,我们选择try-catch

 对一个文件进行流处理时,我们后期都是要进行关闭的,在关闭流时,如果像上面那样创建对象的话,我们的对象变量的范围(有效范围)只能在我们的try语句块内,出了try语句块我们就不能在其他语句块里面对创建的文件对象进行处理,因此我们需要进行相应的变量范围扩大,将对象写入main方法体中,使该对象在main方法中的任何语句块中都可以访问到。如下:

 接下来我们就使用read()方法按单个来读取数据,根据read()方法的定义:在读取数据源对象时只有在读取到的内容返回的值不是-1时,数据才会读取到我们的显示器上,因此我们要使用while循环语句来判断读取到的是否不为-1,并使用一个int值来接收读取到内容返回的码值。

 最后将流关闭,我们运行程序。

 我们之前也提到,read(byte[] b)方法比read()方法读取数据要快,使用数组的读取方式只是多个数组的定义和作为参数传入我们的方法以及在打印时将多个字节转换成字符串,这两步就使得读取的速度快了许多,其他的步骤和read()方法一样,那么我们接下来去看看它的使用:

【 我们的文本内容很少,是看不出来两者之间的差异的,因此我们去手动的添加内容到文本中】

我们看一下多个字符读取的速度: 

 我们看一下单个字符读取的速度: 

 代码:

import java.io.*;
public class FileInputStream_1 {
	public static void main(String[] args) {
		FileInputStream fis=null;   //局部变量必须给初始化值
		String srcFile="e:\MartinOdersky.txt";
		byte[] b=new byte[1024*1024];  //动态数组的长度可以自定义 
		int readIn=0;
		long start=System.currentTimeMillis();  //使用System类下的currentTimeMillis()得到程序当前的毫秒时间
		try {
			fis=new FileInputStream(srcFile);
			try {
		    while((readIn=fis.read(b))!=-1){
		    	System.out.print(new String(b,0,readIn));   //将我们读取的码值转换成字符型输出,即将数组从0到readIn的元素转换成String。
		    }}catch(IOException io) {
		    	io.printStackTrace();
		    	System.out.println("数据读取失败"); }
		} catch (FileNotFoundException e) {
			e.printStackTrace();
			System.out.println("文件路径有误,请检查。");  //如果没有成功创建对象,极有可能是文件路径有误
		}finally {
			System.out.println();
			try {
				if(fis!=null) {
					System.out.println("输入流已关闭");
					fis.close();	}
			}catch(IOException io) {
				io.printStackTrace();
				System.out.println("输入流关闭失败!");}	}
		long end=System.currentTimeMillis();
		System.out.printf("运行时长为%d毫秒",end-start);
	}
}

 FileOutputStream类在读取的文件不存在时可以自己自动创建文件,但是不能创建目录。如下:我们将之前的文件“MartinOdersky.txt”进行copy,写入另外一个文件(这个文件可以是已经存在的也可以是不存在的,但是父目录一定要存在)。

FileOutputStream的使用案例

使用FileOutputStream及FileInputStream拷贝文件到另外一个文件

如下拷贝成功

import java.io.*;
public class FileOutputStream_ {
	public static void main(String[] args) {
		FileInputStream fis=null;   //局部变量必须给初始化值
		FileOutputStream fos=null;   //局部变量必须给初始化值
		String srcFile="e:\MartinOdersky.txt";
		String desFile="e:\Scala'sFarther.txt";
		byte[] b=new byte[1024*1024];  //动态数组的长度可以自定义 
		int readIn=0;
		long start=System.currentTimeMillis();  //使用System类下的currentTimeMillis()得到程序当前的毫秒时间
		try {
			fis=new FileInputStream(srcFile);
			fos=new FileOutputStream(desFile);
			try {
		    while((readIn=fis.read(b))!=-1){
//		    	System.out.print(new String(b,0,readIn));   //将我们读取的码值转换成字符型输出
		        fos.write(b,0,readIn);
		    }}catch(IOException io) {
		    	io.printStackTrace();
		    	System.out.println("数据读取失败"); }
		} catch (FileNotFoundException e) {
			e.printStackTrace();
			System.out.println("文件路径有误,请检查。");  //如果没有成功创建对象,极有可能是文件路径有误
		}finally {
			System.out.println();
			try {
				if(fis!=null) {
					System.out.println("输入流已关闭");
					fis.close();	}
			}catch(IOException io) {
				io.printStackTrace();
				System.out.println("输入流关闭失败!");}	}
		try {
			if(fos!=null) {
				System.out.println("输出流已关闭");
				fos.close();	  //输出流一定要记得关闭,将缓冲的数据刷新
}
		}catch(IOException io) {
			io.printStackTrace();
			System.out.println("输出流关闭失败!");}	
		long end=System.currentTimeMillis();
		System.out.printf("运行时长为%d毫秒",end-start);
	}

}

 【因为字节流处理的数据也可以是图片,音频,压缩包,所以大家将文件类型修改成图片即可】

文件流-字符流

节点流不能用来处理字符类的数据的,因为不同的语言一个字符对应的字节数大不相同,而如果使用字节流来处理字符型数据就会出现乱码,因此在处理字符文本时,java提供了一套专门的类FileReader类(字符输入流)和FileWriter类(字符输出流),其使用和FileInputStream类与FileOutputStream类相似。

FileReader与FileReader使用案例

如下我们出现了乱码,主要原因是因为文件的默认编码是ANSI编码(使用两个字节来代表一个字符的各种汉字延伸的编码格式)

 可能会有人说,我们在对txt文件保存时使用的编码格式就是UTF-8的,但是还是报错,那是因为我们的开发环境IDE(eclipse)的编码格式是GBK的,并且fileReader默认的编码格式是我们开发环境的格式GBK。比较简答粗暴的方法就是将eclipse的编码格式改成UTF-8。

在当前环境下alt+enter打开属性→resource→other→UTF-8

 我们再重新运行程序,如下图所示我们的输出不是乱码了,但是我们的eclipse的编码却有了问题,出现了乱码,因此这种方式不怎么推荐使用。后面我们会认识一个非常好的朋友“处理流(包装流)”里面的转换流“InputStreamReader”,它能够帮我们很好的解决这个乱码问题

 上面的写入操作都是覆盖的形式进行的,如果我们想要使用追加的形式的话可以在文件对象里面加应该参数‘true’,如下:

2,处理流(包装流)

在上面我们认识了节点流,接下来我们去认识有着更为强大的读写功能的类。BufferedReader和BufferedWriter

在BufferedReader类中有属性Reader,该属性意味着只要是Reader的子类(节点流)都可以被封装。使用了修饰器设计模式,不会直接与数据源相连。

处理流包装节点流既可以消除不同节点流的实现差异,也可以提供更方便的方法来完成输入输出。比方说BufferedReader中的readLine()方法,可以读取一行文件---一行被视为由换行符(“n”)回车符(“r”)中的任何一个或随后的换行符终止。

 BufferedReader与BufferedWriter的使用读写数据

我们使用这种方法读写字符时就不会像FileReader和FileWriter那样有乱码,方便高效。

 最后一定要记得关闭BufferedWriter流,不然文件写入不进去。

import java.io.*;
public class BufferedReader1 {
	//使用BufferedReader和BufferedWriter读写字符。
	public static void main(String[] args) {
		String srcPath="e:\MO1.txt";
		String desPath="e:\MO2.txt";
		String line;
		BufferedReader br=null;
		BufferedWriter bw=null;
		long start=System.currentTimeMillis();
		try {
		br=new BufferedReader(new FileReader(srcPath));}
		catch(FileNotFoundException withoutFile) {
			System.out.print(withoutFile);
			System.out.println("没有该文件,请查看目录");
		}
		try {
		bw=new BufferedWriter(new FileWriter(desPath,true));}
		catch(IOException errorWrite) {
			System.out.print(errorWrite);
			System.out.println("没有该盘符或路径表示错误");
		}
		try {
		while((line=br.readLine())!=null) {
			bw.write(line);
			bw.newLine();
//			System.out.println(line);
		}}
		catch(IOException io) {
			System.out.print(io);
			System.out.println("写入失败");
		}
		finally {
			try {
				if(br!=null) {
					br.close();
				}
				if(br!=null) {
					bw.close();
				}
			}
			catch(IOException io) {
				System.out.print(io);
			}
			long end=System.currentTimeMillis();
			System.out.println("文件已成功关闭");
			System.out.println("程序运行结束");
			System.out.println(end-start);
		}
	}
}
对象流

ObjectInputStream和ObjectOutputStream

在使用对象流进行数据的保存时,会将该数据的类型及值一起保存。如int  i=100;

Dog dog=new  Dog("阿拉斯加",6);如果我们要将这些带有数据类型的数据保存的话就需要使用序列化,就是写入的类型不是基本数据类型而是装箱数据类型。例如我们要写入int数据类型的i,那么我们可以使用writeInt(i);double类型的writeDouble();..........

我们需要注意的是,当我们写入一个类(对象)时,是不能直接写入的,需要对其进行序列化(去实现序列化接口即可)因为在java中让某个对象支持序列化机制,则必须让其类是可序列化的,其类须实现两个接口之一:Serializable,Externalizable.一般推荐对象去实现Serializable接口,因为该接口没有任何抽象方法让我们去重写,比较方便。

 【值得注意的是我们在反序列化的时候要按照我们序列化的数据进行输出打印,不然程序不知道我们的数据是int还是double亦或者是对象】

import java.io.*;
public class Alizable {
	public static void main(String[] args) throws FileNotFoundException, IOException,ClassNotFoundException {
	 String srcPath="e:\serializable.dat";
     ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream(srcPath));
     ObjectInputStream ois=new ObjectInputStream(new FileInputStream(srcPath));
     oos.writeInt(66);
     oos.writeDouble(6.6);
     oos.writeUTF("傻狗");
     oos.writeBoolean(false);
     oos.writeObject(new Dog("哈士奇"));
     oos.close();
     System.out.println("序列化结束");
     System.out.println("================反序列化输出数据=============");
    System.out.println( ois.readInt());
    System.out.println( ois.readDouble());
    System.out.println(ois.readUTF());
    System.out.println(ois.readBoolean());
    Object dog=ois.readObject();
    System.out.println(dog);
	}

}
class Dog  implements Serializable{
	String name;
	public Dog(String name) {
		this.name=name;
	}
	public String toString() {
		return "dog's name is:"+name;
	}
}
转换流

InputStreamReader和OutputStreamWriter类解决的是乱码问题

 使用了如上的方法后我们的文件和eclipse编译器就不会出现乱码了

标准输入流和输出流
  • 标准输入流:System.in      InputStream(编译类型)          键盘(默认设备)
  • 标准输出流:System.out    OutputStream(编译类型)        显示器(默认设备)

用于键盘输入的功能我们可以使用Scanner sc=new Scanner(System.in);

我们经常用于输出打印的语句:System.out.print();就是使用的标准输出。

打印流

import java.io.*;

public class Print {
	public static void main(String[] args) throws IOException {
		//字节打印流
		PrintStream out=System.out;
		out.println("你好");
		out.write("你好".getBytes());
		out.close();
		System.setOut(new PrintStream("e:\1.txt"));
		System.out.println("hello new file");
		//字符打印流
		PrintWriter pw=new PrintWriter(new FileWriter("e:\12.txt"));
		pw.print("字符");
		pw.close();
		
	}

}

“MartinOdsky.txt”

洛桑联邦理工学院
洛桑联邦理工学院(法文:École Polytechnique Fédérale de Lausanne, 简称:EPFL),又称瑞士联邦理工(洛桑),位于瑞士联邦洛桑,最初可以追溯到1853年建立的私立学校,后正式成立于1969年, 与姊妹校苏黎世联邦理工学院一起组成瑞士联邦理工学院,是瑞士联邦经济事务、教育与研究部的一部分。 EPFL是欧洲卓越理工大学联盟成员,专注于工程技术、自然科学与建筑学的教育与研究 ,位居2022QS世界大学排名第14位 ,2022U.S. News世界大学排名第70位 ,2021THE世界大学排名第40位 , 2021ARWU软科世界大学排名第91位 。
许多著名人物包括图灵奖得主Joseph Sifakis、诺贝尔化学奖得主Jacques Dubochet、计算机语言Scala发明人Martin Odersky等等都是出自该校。洛桑联邦理工学院拥有核反应堆CROCUS、聚变反应堆Tokamak Fusion reactor、超级计算机Blue Gene/Q、P3生物实验室等研究设施。
On September 5, 1958, Martin odersky was born in Lausanne, Switzerland. 
1958 年 9 月 5 日,Martin Odersky 在瑞士洛桑出生。
He is a professor in the programming research group of EPFL (the leading technical university in Switzerland), who is good at code analysis and programming language. 
他 是EPFL(瑞士领先的技术大学)编程研究组的教授,擅长代码分析和编程语言。
He may have written more Java and scala code than anyone in the world. Because Martin odersky designed the scala programming language generic Java and built the current generation of java compiler javac, which is used by most Java programmers.
他可能比世界上任何一个人写过更多的 Java 和 Scala 代码。因为,Martin Odersky 设计了 Scala 编程语言 Generic Java,并构建了当前一代 Java 编译器 javac,这是大部分 Java 程序员所使用的编译器。
Martin odersky also wrote the scala compiler scalac, which is the cornerstone of the rapid development of the scala community. 
Martin Odersky 也编写了 Scala 编译器 scalac,可谓是 Scala 社区飞速发展的基石。
He is the author of "programming in scala", which is the best-selling Scala book. 
他著有《Programming in Scala》一书,是最畅销的 Scala 书籍。
He has worked at IBM research, Yale University, Karlsruhe University and the University of South Australia. 
他曾经就职于 IBM 研究院、耶鲁大学、卡尔斯鲁厄大学以及南澳大利亚大学。
Before that, he studied with Niklaus Wirth, the founder of Pascal, at the Federal Institute of technology in Zurich, Switzerland, and received a doctorate in 1989.
在此之前,他在瑞士苏黎世联邦理工学院追随 Pascal 创始人 Niklaus Wirth 学习,并于 1989 年获得博士学位。
Scala's name came into being during the first snow in 2002. Martin and his team began designing Scala, which was released in 2003 and underwent a large-scale redesign in 2006. Since then, Scala has grown steadily and rapidly, and v2.0 was released in June 2019 13。 Scala lags behind Java's object-oriented programming and pure data organization in many aspects.
Scala 的名字是在 2002 年第一场雪的时候产生的。Martin 和他的团队开始设计 Scala,它于 2003 年发布,并在 2006 年进行了大规模的重新设计。从那时起,Scala 稳步快速发展,并于 2019 年 6 月发布了 V2.13。尽管 Scala 在很多方面都落后于 Java,但它纯粹的面向对象性质和函数式编程使它能够组织大型面向对象项目以及大数据计算。
Scala has conquered developers with its powerful functions and simple and elegant syntax. In terms of open source projects, spark, Kafka, akka and other companies are vigorously promoting Scala. I believe Scala will have a better future. This multi paradigm programming language is widely used not only in the field of big data, but also in the field of finance.
Scala 以其强大的函数和简单优雅的语法征服了开发人员。在开源项目方面,Spark、Kafka、Akka 等公司都在大力推广 Scala,相信 Scala 的未来会更加精彩。这门多范式编程语言除了在大数据领域,也在金融领域广泛应用。
 

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/850201.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号