欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

(8)IO流技术

程序员文章站 2024-03-04 11:30:47
...

1.IO是什么意思?data source是什么意思?

IO:Input Output

data source:数据流。

 

2.字节流和字符流有什么区别?输入流输出流有什么区别?

    字节流和字符流是流的一种划分,按照处理流的数据单位进行的划分。两类都分为输入和输出操作。在字节流中输出数据主要是使用OutputStream完成,输入是使用InputStream;在字符流中输出主要是使用Writer类来完成,输入流主要使用Reader类来完成。这四个都是抽象类。

    字符流处理的单元为2个字节的Unicode字符,分别是操作字符、字符数组或字符串,而字节流处理单元为1个字节,操作字节和字节数组。字节流是最基本的,所有的InputStream和OutputStream的子类都是字节流,主要用来处理二进制数据,它是按字节来处理的。但实际中很多数据都是文本,又提出了字符流的概念,它是按虚拟机的编码来处理,也就是说要进行字符集的转化,这两个之间通过InputStreamReader、OutputStreamWriter(转换流)来关联,实际上是通过byte()和String来关联的。

   流就像管道一样,在程序和文件之间,输入和输出的方向是针对程序而言,向程序中读入读入东西,就像输入流,从程序中向外读东西,就是输出流。输入流是得到数据,输出流是输出数据。

 

3.节点流和处理流有什么区别?

节点流和处理流是把流按照功能的另一种划分。

节点流,可以从或向一个特定的地方(节点)读写数据。

处理流是对一个已存在的流的连接和封装,通过所封装的流的功能调用实现数据读写。如BufferReader。处理流的构造方法总是要带一个其他的流对象做参数。一个流对象经过其他流的多次包装,称为流的链接。

 

4.Word文档能使用字符流操作吗?

不能。因为Word文档不是纯文本文件,除了文字还包含很多格式信息。不能用字符流操作,可以用字节流操作。

 

5.BufferedInputStream和BufferedOutputStream的特点?

    BufferedInputStream和BufferedOutputStream分别是【缓冲】字节输入、输出流,还有【缓冲】字符输入输出流(BufferedReader和BufferedWriter)。

    缓冲流是处理流,他不是直接连接数据源/目的地,而是以一个节点流为参数,在节点流的基础上,提供一些简单参数。

    先说不带缓冲的流的工作原理吧:它读取到一个字节/字符,就向用户指定的路径写进去,读一个写一个,所以就慢了。带缓冲的流的工作原理:读取到一个字节/字符,先不输出,等凑足了缓冲的最大容量后一次性写进去,从而提高了工作效率。

优点:减少对硬盘的读取次数,降低对硬盘的损耗。

 

6.使用BufferedReader和BufferedWriter实现文本的拷贝。

package IO;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.Reader;
import java.io.Writer;

public class CopyFile {

	public static void main(String[] args) throws Exception {
		//第一部分:准备从文件读数据到程序
		//创建读取对象reader
		Reader reader = new FileReader(new File("e:\\a.txt"));
		//创建缓冲流包装reader
		BufferedReader br = new BufferedReader(reader);
		
		//第二部分:准备从程序写到文件
		//创建写入对象writer
		Writer writer = new FileWriter(new File("e:\\a2.txt"));
		//创建缓冲包装对象
		BufferedWriter bw = new BufferedWriter(writer);
		
		String str = null;
		//用循环边读边写
		while((str=br.readLine()) != null) {
			bw.write(str);
			bw.newLine();
		}
		
		//清除缓冲区
		bw.flush();
		//copy完成后关闭资源
		bw.close();
		br.close();
	}
}

(8)IO流技术

 

7.InputStreamReader和OutputStreamWriter的作用是?

二者都是转换流,从字节流转换成字符流,是包装流,以一个节点流为参数,提供一些方便读写【字符】的方法。

package IO;

import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;

public class InputStreamReaderDemo {

	public static void main(String[] args) throws Exception {
		//节点流
		InputStream is = new FileInputStream("e:\\a.txt");
		//处理流,把字节流转换成字符流
		InputStreamReader isr = new InputStreamReader(is,"utf-8");
		int temp = 0;
		//用转换流对象isr进行读写操作,以字符(而不是字节)为单位读取文本文件,方便操作
		while((temp = isr.read()) != -1) {
			System.out.print((char) temp +" ");//打印出来的字符会以空格隔开
		}
		isr.close();
		is.close();
	}

}

(8)IO流技术

 

 

 

8.PrintStream打印流经常用于什么情况?System.out是打印流吗。

PrintStream:字节打印流,是OutputStream的实现类。提供了多个重载的print,println等方法,可以方便地向文本文件写入数据。

System.out是字节打印流(PrintStream的对象),它被称作标准的输出流,输出的目的地是标准的输出设备,即显示器。所以,当我们使用System.out.print时会向屏幕(显示器)输出数据。

 

9.实现字节数组和任何基本类型、引用类型执行的相互转换。

提示:使用ByteArrayInputStream和ByteArrayOutputStream。

(1)字节数组和基本类型之间的转换,以boolean为例:

    ①输出一个boolean类型的数据:

boolean flag = true;//先定义一个boolean类型的变量
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(baos);
dos.writeBoolean(flag);
	
byte[] b = baos.toByteArray();
//接下来可以把byte数组建成一个数据包(DatagramPacket)发送出去;

     ②读取一个boolean类型的数据:

byte[] b = new byte[1024];
//我们已接收到包含一个Boolean类型数据的数据包;数据信息已经包含在byte数组b里,接下来就把boolean类型的数据读出来并保持原类型
	
ByteArrayInputStream bais = new ByteArrayInputStream(b);
DataInputStream dis = new DataInputStream(bais);
boolean flag = dis.readBoolean();//这样数据就读出来了并保持着原来的数据类型

 

(2)字节数组和引用类型之间的转换:

  ①输出一个引用类型信息:

//先建一个类,如User
User user = new User();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(user);

byte[] b = baos.toByteArray();
//接下来可以把byte数组构建成一个数据包发送出去

  ②读取一个引用类型信息

byte[] b = new byte[1024];
//我们已接收到包含一个User类型数据的数据包(代码略)
//数据信息已经包含在byte数组b里,接下来就把User类型的数据读出来并保持原类型
ByteArrayInputStream bais = new ByteArrayInputStream(b);
ObjectInputStream ois = new ObjectInputStream(bais);
User user = (User)ois.readObject();//这样数据就读出来了并保持着原来的数据类型

 

10.DataInputStream和DataOutputStream的特点是?

  二者都是处理流,要以一个节点流为参数;二者被称为数据流,是用来操作基本数据类型的。用DataInputStream写入一个类型的数据,用DataOutputStream读出数据时可以保持类型不变。

  如:用DataInputStream写入一个int类型数据,用DataOutputStream读出来的还是一个int数据,即可以直接当作int类型的数据来进行操作,不用作任何转换。

数据流特点:

     ①写入是什么类型的数据,读出的是相应类型的数据

     ②要先写后读,用DataOutputStream流写,用DataInputStream流读

     ③读写顺序要一致,否则会报EOF(End of file)异常

     ④数据流可以跨平台写入和读出,适合网路应用

 实例:

package IO;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class DataStreamDemo {

	public static void main(String[] args) throws IOException {
		//1.写数据
		OutputStream os = new FileOutputStream(new File("e:\\a1.txt"));//构建节点流
		DataOutputStream dos = new DataOutputStream(os);//用数据流包装节点流
		
		int n = 123456;
		String str = "CSDN博客";
		
		dos.writeInt(n);//用数据流写一个int类型数据
		dos.writeUTF(str);//String
		dos.writeDouble(3.14);//double
		dos.writeChar('周');//char
		dos.writeBoolean(true);//boolean
		
		
		//2.读数据,(按上面写的顺序才行)
		InputStream is = new FileInputStream(new File("e:\\a1.txt"));
		DataInputStream dis = new DataInputStream(is);
		int n1 = dis.readInt(); //用数据流读出刚才写入的int类型数据
		String str1 = dis.readUTF();
		double d = dis.readDouble();
		char c = dis.readChar();
		boolean flag = dis.readBoolean();
		
		//打印输出用数据流读出的数据
		System.out.println(n1);
		System.out.println(str1);
		System.out.println(d);
		System.out.println(c);
		System.out.println(flag);

		//关闭资源
		dis.close();
		dos.close();
	}

}

运行结果:(8)IO流技术

 

11.中文乱码是怎么造成的?Unicode字符集是几个字节表示一个字符,为什么需要utf-8?

字符流的读写根据需要,设置编码方式,若编码方式设置不当,就会出现中文乱码。

Unicode字符集2个字节表示一个字符。

 

12.序列化和反序列化指的是什么?

(1)序列化:

        将对象以byte流的形式写入到文件中-》序列化;

        将要被序列化对象的类要实现Serializable接口。 

(2)反序列化:

         将文件中的数据以byte流的形式读到程序中来,依然是一个对象-》反序列化

 

13.想序列化某个类的对象,该类必须实现Serializable借口吗?说说该接口的特点。

要序列化的对象必须实现Serializable接口,以启动序列化的功能。

Serializable接口特点:

①需要被序列化的对象的类必须实现Serializable接口;

②给类加个序列化编号,即给类定义一个标记,例:public static final long serialVersionUID = 1L;

新的修改后的类还可以操作曾经序列化的对象;

③静态类是不能被序列化的(序列化只能对堆中的对象进行序列化,不能对"方法区"中的对象进行序列化);

④不需要序列化的字段前加transient,如:private transient String password;

 

15.代码实现从源目录拷贝文件到目标文件(结合递归算法)。

package IO;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class CopyDir {

	public static void main(String[] args) {
		try {
			copyDirectiory("E:\\learning_note","E:\\learning_note2");
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	/**
	 * 复制单个文件
	 * @param sourceFile
	 * @param targetFile
	 * @throws IOException
	 */
	private static void copyFile(File sourceFile, File targetFile) throws IOException {
		BufferedInputStream inBuff = null;
		BufferedOutputStream outBuff = null;
		
		try {
			//新建文件输入流
			inBuff = new BufferedInputStream(new FileInputStream(sourceFile));
			//新建文件输出流
			outBuff = new BufferedOutputStream(new FileOutputStream(targetFile));
			//缓冲数组
			byte[] b = new byte[1024*5];
			int len;
			while((len = inBuff.read(b)) != -1) {
				outBuff.write(b, 0, len);
			}
			
			//刷新此缓冲的输出流
			outBuff.flush();
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally{
		
			//关闭流
			if(inBuff != null) {
				inBuff.close();
			}
			if(outBuff != null) {
				outBuff.close();
			}
		}
		
	}
	
	/**
	 * 复制目录
	 * @param sourceDir
	 * @param targetDir
	 * @throws IOException
	 */
	private static void copyDirectiory(String sourceDir,String targetDir) throws IOException {
		//检查源目录
		File fSourceDir = new File(sourceDir);
		if(!fSourceDir.exists() || !fSourceDir.isDirectory()) {//不存在或不是目录结构
			return;
		}
		//检查目标目录,如不存在就创建
		File fTargetDir = new File(targetDir);
		if(!fTargetDir.exists()) {
			fTargetDir.mkdirs();
		}
		//遍历源目录下的文件或目录
		File[] file = fSourceDir.listFiles();
		for(int i=0; i<file.length; i++) {
			if(file[i].isFile()) {
				File sourceFile = file[i]; //源文件
				File targetFile = new File(fTargetDir,file[i].getName());//目标文件
				copyFile(sourceFile, targetFile);
				
			}
			//递归复制子目录
			if(file[i].isDirectory()) {
				//准备复制的源文件夹
				String subSourceDir = sourceDir+File.separator+file[i].getName();
				//准备复制的目标文件夹
				String subTargetDir = targetDir+File.separator+file[i].getName();
				//复制子目录
				copyDirectiory(subSourceDir,subTargetDir);
			}
		}	
	}
}

(8)IO流技术

 

16.代码实现统计几个.java文件的行数的功能。

package IO;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

public class CountLines {
	private int count;

	/**
	 * 统计一个Java文件的行数
	 * 
	 * @throws IOException
	 */
	private void countLine(File sourceFile) throws IOException {
		BufferedReader br = null;
		try {
			// 新建文件输入流
			br = new BufferedReader(new FileReader(sourceFile));
			while (br.readLine() != null) {
				count++;
			}
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			br.close();
		}
	}

	/**
	 * 统计一个目录下所有Java文件的行数
	 * @throws IOException 
	 */
	private void countDir(String sourceDir) throws IOException {
		// 检查源目录
		File fSourceDir = new File(sourceDir);
		if (!fSourceDir.exists() || !fSourceDir.isDirectory()) {
			System.out.println("源目录不存在");
			return;
		}
		//遍历目录下的文件或目录
		File[] file = fSourceDir.listFiles();
		for(int i=0; i<file.length; i++) {
			if(file[i].isFile()) {
				if(file[i].getName().toLowerCase().endsWith(".java")) {
					countLine(file[i]);
				}
			}
			//递归统计代码行数
			if(file[i].isDirectory()) {
				//准备统计的文件夹
				String subSourceDir = sourceDir+File.separator+file[i].getName();
				//统计子目录
				countDir(subSourceDir);
			}
		}
		
	}

	public static void main(String[] args) throws IOException {
		CountLines cl = new CountLines();
		cl.countDir("e:\\javaFile");
		System.out.println(cl.count);
	}

}