第十五章 I/O(输入/输出)

15.1 输入/输出流

流是一组有序的数据序列,可分为输入流和输出流两种。

程序从指向源的输入流中读取源中数据,源可以是文件、网络、压缩包或者其他数据源

输出流的指向是数据要到达的目的地,输出流的目标可以是文件、网络、压缩包、控制台和其他数据输出目标。 

15.1.1 输入流

InputStream类是字节输入流的抽象类,他是所有字节输入流的父类。InputStream类的具体层次结构如下:

  • read()方法:从输入流中读取数据的下一字节。返回0~255的int字节值。如果因为已经到达流末尾而没有可用的字节,则返回值为-1.
  • read(byte[]b):从输入流中读入一定长度的字节,并以整数的形式返回字节数。
  • mark(int readlimit)方法: 在输入流的当前位置放置一个标记,readlimit参数告知此输入流再标记位置失效之前允许读取的字节数。
  • reset()方法:将输入指针返回到当前所做的标记处。
  • skip(long n)方法:跳过输入流上的n个字节并返回实际跳过的字节数。
  • markSupported()方法:如果当前流支持mark()/reset()操作就返回turn。
  • close方法:关闭此输入流并释放与该流关联的所有系统资源。

并不是所有的 InputStream类的子类都支持 InputStream 类中定义的所有方法、如skip0、mark0、Tset0等方法只对某些子类有用。

 Java 中的字符是Unicode 编码,是双字节的。InputStream 类是用来处理字节的,并不适合处理字符文本。Java为字符文本的输入专门提供了一套单独的类,即Reader 类,但Reader 类并不是InputStear类的替换者,只是在处理字符串时简化了编程。Reader 类是字符输入流的抽象类,所有字符输入流的实现都是它的子类。Reader 类的具体层次结构如图所示。

15.1.2 输出流 

OutputStream类是字节输出流的抽象类,此抽象类是表示输出字节流的所有类的超类

OutputStream类中的所有方法均返回void,在遇到错误时会引发IOException异常,

1.write(intb)方法:将指定的字节写入此输出流。

2. writebyte[]b)方法:将b个字节从指定的byte 数组写入此输出流。

3.write(byte[ b,int off,int len)方法:将指定 byte 数组中从偏移量of开始的len个字节写入此输

出流。

4.fush0方法:彻底完成输出并清空缓存区。

5.close0方法:关闭输出流。

Writer 类是字符输出流的抽象类,所有字符输出类的实现都是它的子类。Writer 类的层次结构如:

15.2 File类

File 类是 java.io包中唯一代表磁盘文件本身的类。File类定义了一些与平台无关的方法来操作文件,可以通过调用 File类中的方法,实现创建、删除、重命名文件等操作。File类的对象主要用来获取文件本身的一些信息,如文件所在的目录、文件的长度、文件读写权限等。数据流可以将数据写入文件中,文件也是数据流最常用的数据媒体


15.2.1 文件的创建与删除

可以使用File类创建一个文件对象。通常使用以下3种构造方法来创建文件对象。

1. File(String pathname)

该构造方法通过将给定的路径名字符串转换为抽象路径名来创建一个新File实例。语法如下:

new File(String pathname)

其中,pathname代表路径名称(包含文件名)。例如

File file = new File("d:/1.txt");

2. File(String parent,String child)

该构造方法根据定义的父路径和子路径字符串(包含文件名)创建一个新的File对象。语法如

new File(String parent, String child)

3. File(File f, String child)

该构造方法根据f抽象路径名和child路径名字符串创建一个新File实例。语法如下

new File(File f,String child)

f:父路径对象,如D:/doc/。

child:子路径字符串,如letter.txt。

当使用 File类创建一个文件对象后,例如:

Re lie =new FileCword.txt");

知果当前目录中不存在名称为word的文件,File 类对象可通过调用createNewFile0方法创建一个名称

wndtxt 的文件;如果存在word.txt文件,可以通过文件对象的deleteO方法将其删除,如例15.1所示。

例题

import java.io.File;
import java.io.IOException;
public class FileText {
	private static File[] files;
 
 
	public static void main(String[] args) {
		// TODO Auto-generated method stub
	/*	File file=new File("c:\\happy\\word.txt"); //创建文件对象
		if(file.exists()) {//如果文件存在
			file.delete(); //如果文件删除
			System.out.println("文件已删除");       printAllFiles(f);
		}
		else {                                 //如果文件不存在
				try {                     //try语句块捕捉可能出现的异常
					file.createNewFile(); //创建新文件
					System.out.println("文件已创建");
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
		}*/
		File file=new File("C:\\happy");
		printAllFiles(file);
	}
 
 
		private static void printAllFiles(File file) {
		File[] files = file.listFiles();
		for(File f : files){
		if(f.isDirectory()) {
		System.out.println("------- " + f.getName() + " -------");
		printAllFiles(f);
		}else {
			System.out.println(f.getName());
		}
	}
}
		}

运行结果如下:

15.2.2 获取文件信息

例题15.2

import java.io.File;
 
public class FileText2 {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		File file=new File("c:\\happy\\word.txt"); //创建文件对象
		if(file.exists()) {
			String name=file.getName();  //获取文件名称
			long length=file.length();  //获取文件长度
			boolean hidden=file.isHidden(); //判断文件是否为隐藏文件
			System.out.println("文件名称:"+name);
			System.out.println("文件长度是:"+length);
			System.out.println("该文件是隐藏文件吗?"+hidden);
		}
		else {//如果文件不存在
			System.out.println("该文件不存在");
		}
	}
 
}

运行结果如下: 

15.3 文件输入/输出流

程序运行期间,大部分数据都在内存中进行操作,当程序结束或关闭时,这些数据将消失。如果需要将数据永久保存,可使用文件输入/输出流与指定的文件建立连接,将需要的数据永久保存到文件中。本节将讲解文件输入/输出流。

15.3.1  FilelnputStream 与 Fileouisieam 类

FilelnputStream 类与FileOutputStream类都用来操作磁盘文件。如果用户的文件读取需求比较简单,则可以使用FileInputStream 类,该类继承自 InputStream 类。FileOutputStream 类与FilelmputStream类对应,提供了基本的文件写入能力。FileOutputStream类是OutputStream类的子类。

FileinputStream 类常用的构造方法如下:

 FileinputStream(String name)。

 FilelnputStream(File file)。

第一个构造方法使用给定的文件名 name 创建一个FilelnputStream对象,第二个构造方法使用File对象创建FilelnputStream 对象。第一个构造方法比较简单,但第二个构造方法允许在把文件连接输入流之前对文件做进一步分析。

FileOutputStream 类有与FilelnputStream类相同的参数构造方法,创建一个FileOutputStream 对象时,可以指定不存在的文件名,但此文件不能是一个已被其他程序打开的文件。下面的实例就是使用FileinputStream 类与FileOutputStream类实现文件的读取与写入功能的。

例题15.3

import java.io.File;                   //缓冲流                //字节流  FileOutputStream输出流   FileInputStream输入流
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
 
public class FileStreamDemo {
	public static void main(String[] args) throws IOException {
		// TODO Auto-generated method stub
		File file = new File("C:\\happy\\word.txt");
		FileOutputStream out = new FileOutputStream(file); //输出字节流
		byte[]by = "hello world".getBytes(); 
		out.write(by);  //往文件中写入数据
		out.close();
		
		FileInputStream in = new FileInputStream(file);
		byte[] by1 = new byte[1024];
		int len = in.read(by1);
		System.out.println(new String(by1,0,len));//从零号位开始打印,只打印len长度
	}
 
}

运行结果如下:

15.3.2 FileReader 和 FileWriter类

使用FileOutputStream 类向文件中写入数据与使用FilelnputStream类从文件中将内容读出来,都存在一点不足,即这两个类都只提供了对字节或字节数组的读取方法。由于汉字在文件中占用两个字节,如果使用字节流,读取不好可能会出现乱码现象,此时采用字符流 FileReader 类或 FileWriter 类即可是兔这种现象。

FileReader 类和 FileWriter 类对应了FileInputStrcam 类和FileOutputStrcam 类。FileReader 类顺序地读取文件,只要不关闭流,每次调用 read0方法就顺序地读取源中其余的内容,直到源的末尾或流被关闭.

 例题15.4

import java.io.BufferedReader;                //文件流
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;                        //字符流   FileWriter输出流  FileReader输入流
import java.io.FileWriter;
import java.io.IOException;
 
public class FileReaderDemo {
             
	public static void main(String[] args) throws IOException {
		// TODO Auto-generated method stub
		File file = new File("C:\\happy\\word.txt");
		FileWriter writer = new FileWriter(file);  //输出字符流
		//char[]by = new char[] {'h','e','l','l','o'}; //输入数据
		//带缓存的输出流
		BufferedWriter bw = new BufferedWriter(writer); //BufferedWriter缓存流
		//String str="门前大桥下,游过一群鸭";
		bw.write("门前大桥下,游过一群鸭");
		bw.newLine();                       //换行
		bw.write("快来快来数一数,二四六七八");
		bw.newLine();
		bw.write("咕嘎咕嘎,真呀真多");
		bw.newLine();
		bw.write("数不清到底多少鸭");
		bw.close();
		//writer.write(str);  //往文件中写入数据
		writer.close();
		
		 FileReader reader = new  FileReader(file);
	 
		 /*char[] ch1 = new char[1024];
		int len = reader.read(ch1);
		System.out.println(new String(ch1,0,len));*/
		 
		 BufferedReader br =new  BufferedReader(reader);
		 String s1 = br.readLine();
		 System.out.println("第一行:"+ s1);
		System.out.println("第二行:"+ br .readLine());
		 System.out.println("第三行:"+ br .readLine());
		System.out.println("第四行:"+ br .readLine());
		reader.close();
	}
 
}

运行结果如下:

15.4 带缓存的输入/输出流

缓存是VO的一种性能优化。缓存流为VO流增加了内存缓存区,使得在流上执行skip0、markO和reset0方法都成为可能

15.4.1  BufferedInputStream 与BufferedOutputStream类

BufferedInputStream 类可以对所有 InputStream 类进行带缓存区的包装以达到性能的优化。BufferedInputStream 类有两个构造方法:

1. BufferedInputStream(InputStream in)。

2.BufferedInputStream(InputStream in,int size).

第一种形式的构造万法创建了一个有32个字节的缓存区;第二种形式的构造方法按指定的大小来创建缓存区。一个最优的缓存区的大小,取决于它所在的操作系统、可用的内存空间以及机器配置。从构造方法可以看出,BufferedInputStream对象位于InputStream类对象之后。图15.7描述了带缓存的字节流读取文件的过程。

使用BufferedOutputStrcam 类输出信息和仅用0utputStream 类输出信息完全一样,只不过BufferedOutputStream 有一个fushO方法用来将缓存区的数据强制输出完。BufferedOutputStream类也有两个构造方法:

1. BufferedOutputStream(OutputStream in)。

2. BufferedOutputStream(OutputStream in,int size)。

第一种构造方法创建一个有32个字节的缓存区,第二种构造方法以指定的大小来创建缓存区。


15.4.2 BufferedReader 与 BufferedWriter类

BufferedReader 类与BufferedWriter 类分别继承Reader 类与Writer 类。这两个类同样具有内部缓存机制,并能够以行为单位进行输入/输出。

根据BufferedReader类的特点,可以总结出如图15.8所示的带缓存的字符数据读取文件的过程。

BufferedReader 类常用的方法如下:

区readO方法:读取单个字符。

区readLine0方法:读取一个文本行,并将其返回为字符串。若无数据可读,则返回null.

BufferedWriter 类中的方法都返回void。常用的方法如下:

write(String s,int off, int len)方法:写入字符串的某一部分。

flushO方法:刷新该流的缓存。

newLineO方法:写入一个行分隔符。

在使用 BufferedWriter 类的WriteO方法时,数据并没有立刻被写入输出流,而是首先进入缓存区中。如果想立刻将缓存区中的数据写入输出流,一定要调用flushO方法。

例题15.5

 
 
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
 
public class BufferedDemo {
	public static void main(String args[]) {
		String content[] = { "好久不见", "最近好吗", "常联系" };// 写入的内容
		File file = new File("C:\\happy\\word.txt"); // 创建文件对象
		try {
			FileWriter fw = new FileWriter(file); // 文件字符输出流
			BufferedWriter bw = new BufferedWriter(fw); // 换成输出流
			for (int k = 0; k < content.length; k++) { // 遍历要输入的内容
				bw.write(content[k]); // 写入字符串
				bw.newLine(); // 写入一个换行符
			}
			bw.close(); // 关闭缓冲输出流
			fw.close(); // 关闭文件字符输出流
		} catch (IOException e) {
			e.printStackTrace();
		}
		try {
			FileReader fr = new FileReader(file); // 文件字符输入流
			BufferedReader br = new BufferedReader(fr);// 缓冲输入流
			String tmp = null; // 作为缓冲的临时字符串
			int i = 1; // 行数
			// 从文件中读出一行,如果读出的内容不为null,则进入循环
			while ((tmp = br.readLine()) != null) {
				System.out.println("第" + i + "行:" + tmp); // 输出读取的内容
				i++; // 行数递增
			}
			br.close(); // 关闭缓冲输入流
			fr.close(); // 关闭文件字符输入流
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}//例题15.5

运行结果如下:

15.5 数据输入/输出流

数据输入/输出流(DataInputStream 类与DataOutputStream类)允许应用程序以与机器无关的方式从底层输入流中读取基不)ava数据类型。也就是说,当读取一不数据时,不必再关心这个数值应当是哪种字节。DatalnputStream 类与DataOutputStream类的构造方法如下。

1. DatalnputStream(InputStream in):使用指定的基础 InputStream 对象创建一个DataInputStream

对象。

2. DataOutputStream(OutputStream out):创建一个新的数据输出流,将数据写入指定基础输出流。

DataOutputStream 类提供了将字符串、double 数据、int 数据、boolean数据写入文件的方法。其中,将字符串写入文件的方法有 3种,分别是writeBytes(String s)、writeChars(String s)、writeUTF(String s)。由于Java 中的字符是Unicode 编码,是双字节的,writeBytesO方法只是将字符串中的每一个字符的低字节内容写入目标设备中;而writeCharsO方法将字符串中的每一个字符的两个字节的内容都写到目标设备中;writeUTFO方法将字符串按照UTF 编码后的字节长度写入目标设备,然后才是每一个字节的UTF 编码。

DatalnputStream 类只提供了一个readUTFO方法返回字符串。这是因为要在一个连续的字节流读取一个字符串,如果没有特殊的标记作为一个字符串的结尾,并且不知道这个字符串的长度,就无法知道读取到什么位置才是这个字符串的结束。DataOutputStream 类中只有writeUTFO方法向目标设备中写入字符串的长度,所以也能准确地读回写入字符串。

 例题15.6

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
 
public class DataStreamDemo {
 
	public static void main(String[] args) throws IOException {
		// TODO Auto-generated method stub
		File file = new File("C:\\happy\\word.txt"); // 创建文件对象
		FileOutputStream fos = new FileOutputStream(file);
		DataOutputStream dos = new DataOutputStream(fos);
		dos.writeBoolean(false);
		dos.writeUTF("你好世界");
		dos.writeDouble(13.25);
		dos.close();
		fos.close();
		
		
		FileInputStream fis = new FileInputStream(file);
		DataInputStream dis = new DataInputStream (fis);
		System.out.println(dis.readBoolean());
		System.out.println(dis.readUTF());//输出字符串
		System.out.println(dis.readDouble());
		dis.close();
		fis.close();
		
	}
 
}

运行结果如下:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
```c++ #include <iostream> #include <fstream> #include <vector> #include <algorithm> using namespace std; const int buffer_size = 5; // 缓冲区大小 const int block_size = 10; // 磁盘块大小 // 缓冲区结构体 struct Buffer { int data[buffer_size]; int size; }; // 写入磁盘块 void write_block(int block_num, vector<int>& data) { ofstream fout(to_string(block_num)); for (int i = 0; i < block_size; i++) { if (i < data.size()) { fout << data[i] << endl; } else { fout << -1 << endl; // 块剩余部分用-1填充 } } fout.close(); } // 读取磁盘块 vector<int> read_block(int block_num) { vector<int> data; ifstream fin(to_string(block_num)); int num; while (fin >> num) { if (num != -1) { data.push_back(num); } else { break; } } fin.close(); return data; } // 内存中的排序 void sort_buffer(Buffer& buffer) { sort(buffer.data, buffer.data + buffer.size); } // 归并两个有序数组 vector<int> merge(vector<int>& a, vector<int>& b) { vector<int> res; int i = 0, j = 0; while (i < a.size() && j < b.size()) { if (a[i] == b[j]) { res.push_back(a[i]); i++; j++; } else if (a[i] < b[j]) { res.push_back(a[i]); i++; } else { res.push_back(b[j]); j++; } } while (i < a.size()) { res.push_back(a[i]); i++; } while (j < b.size()) { res.push_back(b[j]); j++; } return res; } // 从缓冲区读取数据 vector<int> read_from_buffer(Buffer& buffer, int num) { vector<int> res; int i = 0; while (i < buffer.size && res.size() < num) { res.push_back(buffer.data[i]); i++; } buffer.size -= res.size(); for (int j = i; j < buffer.size; j++) { buffer.data[j-i] = buffer.data[j]; } for (int j = buffer.size; j < buffer_size; j++) { buffer.data[j] = -1; } return res; } // 向缓冲区写入数据 void write_to_buffer(Buffer& buffer, vector<int>& data) { int i = 0; while (i < data.size() && buffer.size < buffer_size) { buffer.data[buffer.size] = data[i]; buffer.size++; i++; } } // 交操作 vector<int> intersect(vector<int>& a, vector<int>& b) { vector<int> res; int i = 0, j = 0; while (i < a.size() && j < b.size()) { if (a[i] == b[j]) { res.push_back(a[i]); i++; j++; } else if (a[i] < b[j]) { i++; } else { j++; } } return res; } // 并操作 vector<int> merge(vector<int>& a, vector<int>& b) { vector<int> res; int i = 0, j = 0; while (i < a.size() && j < b.size()) { if (a[i] == b[j]) { res.push_back(a[i]); i++; j++; } else if (a[i] < b[j]) { res.push_back(a[i]); i++; } else { res.push_back(b[j]); j++; } } while (i < a.size()) { res.push_back(a[i]); i++; } while (j < b.size()) { res.push_back(b[j]); j++; } return res; } // 两阶段归并排序 vector<int> two_phase_merge_sort(vector<vector<int>>& data) { // 第一阶段:内存排序 for (auto& d : data) { sort(d.begin(), d.end()); } // 第二阶段:归并 while (data.size() > 1) { vector<vector<int>> tmp; for (int i = 0; i < data.size(); i += 2) { if (i == data.size() - 1) { tmp.push_back(data[i]); } else { tmp.push_back(merge(data[i], data[i+1])); } } data = tmp; } return data[0]; } // 交集运算 void intersect_operation(vector<int>& a, vector<int>& b) { vector<vector<int>> blocks_a, blocks_b; int block_num_a = 0, block_num_b = 0; // 将a、b分块存储到磁盘 for (int i = 0; i < a.size(); i += block_size) { vector<int> block_data_a = read_from_buffer(a_buffer, block_size); write_to_buffer(a_buffer, block_data_a); blocks_a.push_back(block_data_a); write_block(block_num_a, block_data_a); block_num_a++; } for (int i = 0; i < b.size(); i += block_size) { vector<int> block_data_b = read_from_buffer(b_buffer, block_size); write_to_buffer(b_buffer, block_data_b); blocks_b.push_back(block_data_b); write_block(block_num_b, block_data_b); block_num_b++; } // 对磁盘上的数据进行排序和归并 vector<vector<int>> sorted_blocks_a, sorted_blocks_b; for (int i = 0; i < block_num_a; i++) { sorted_blocks_a.push_back(read_block(i)); } for (int i = 0; i < block_num_b; i++) { sorted_blocks_b.push_back(read_block(i)); } vector<int> sorted_a = two_phase_merge_sort(sorted_blocks_a); vector<int> sorted_b = two_phase_merge_sort(sorted_blocks_b); // 对有序数组进行交集操作 vector<int> res = intersect(sorted_a, sorted_b); // 输出结果 cout << "交集运算结果为:" << endl; for (auto& num : res) { cout << num << " "; } cout << endl; } // 并集运算 void merge_operation(vector<int>& a, vector<int>& b) { vector<vector<int>> blocks_a, blocks_b; int block_num_a = 0, block_num_b = 0; // 将a、b分块存储到磁盘 for (int i = 0; i < a.size(); i += block_size) { vector<int> block_data_a = read_from_buffer(a_buffer, block_size); write_to_buffer(a_buffer, block_data_a); blocks_a.push_back(block_data_a); write_block(block_num_a, block_data_a); block_num_a++; } for (int i = 0; i < b.size(); i += block_size) { vector<int> block_data_b = read_from_buffer(b_buffer, block_size); write_to_buffer(b_buffer, block_data_b); blocks_b.push_back(block_data_b); write_block(block_num_b, block_data_b); block_num_b++; } // 对磁盘上的数据进行排序和归并 vector<vector<int>> sorted_blocks_a, sorted_blocks_b; for (int i = 0; i < block_num_a; i++) { sorted_blocks_a.push_back(read_block(i)); } for (int i = 0; i < block_num_b; i++) { sorted_blocks_b.push_back(read_block(i)); } vector<int> sorted_a = two_phase_merge_sort(sorted_blocks_a); vector<int> sorted_b = two_phase_merge_sort(sorted_blocks_b); // 对有序数组进行并集操作 vector<int> res = merge(sorted_a, sorted_b); // 输出结果 cout << "并集运算结果为:" << endl; for (auto& num : res) { cout << num << " "; } cout << endl; } int main() { // 初始化缓冲区 Buffer a_buffer = {{-1, -1, -1, -1, -1}, 0}; Buffer b_buffer = {{-1, -1, -1, -1, -1}, 0}; // 初始化两个集合 vector<int> a = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; vector<int> b = {5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19}; // 进行交集运算 intersect_operation(a, b); // 进行并集运算 merge_operation(a, b); return 0; } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值