9.3.3 文件字节流
InputStream和OutputStream 都是抽象类不能实例化,因此在实际的应用中都使用的是它们的子类,这些子类在实现其超类方法的同时又定义了特有的功能,用于不同的场合。
FileInputStream 用于顺序访问本地文件,从超类继承read、close方法,对文件进行操作。
FileOutputStream 用于向一个本地文件写数据。它从超类继承write和close方法。
public class FileStreamCopy {
public static void main(String[] args) throws IOException {
int size;
// 声明实例化输入流对象
FileInputStream f = new FileInputStream("E:/Java知识总结/HTML标签.txt");
// 声明实例化输出流对象
FileOutputStream fout = new FileOutputStream("E:/Java知识总结/copyHTML标签.txt");
System.out.println("Total Available Bytes: " + (size = f.available()));
int n = size / 30;
System.out.println("First " + n + " byte of the file one read() at a time");
// 使用read() 和write()
for (int i = 0; i < n; i++) {
fout.write(f.read());
}
System.out.println("Still Available: " + f.available());
System.out.println("Reading the next " + n + "with one read(b[])");
byte b[] = new byte[n];
if (f.read(b) != n) {
System.out.println("couldn't read " + n + "bytes");
}
fout.write(b);
System.out.println("Still Available:" + f.available());
System.out.println("Reading the rest bytes with read(b[],offset,len)");
int count = 0;
// 循环读取
while ((count = f.read(b, 0, n)) != -1) {
fout.write(b, 0, n);
}
System.out.println("Still Available:" + f.available());
// 关闭流
f.close();
fout.flush();
fout.close();
}
}
9.3.4 过滤流
过滤流在读/写数据的同时可以对数据进行处理,它提供了同步机制,使得某一时刻只有一个线程可以访问一个I/O流,以防止多个线程同时对一个I/O流进行操作带来的意想不到的结果。
过滤流扩展了输入输出流的功能,典型的扩展是缓冲、字符字节转换和数据转换。为了提高数据的传输效率,为一个流配备缓冲区(Buffer),称为缓冲流。
当向一个缓冲流写入数据时,系统将数据发送到缓冲区,而不是直接发送到外部设备,缓冲区自动记录数据。当缓冲区满时,系统将全部数据发送到外部设备。
当从一个缓冲区读取数据时,系统实际上从缓冲区中读取数据。当缓冲区空时,系统自动从相关设备读取数据,并读取尽可能多的数据充满缓冲区。
常用的缓冲输入流有:
BufferedInputStream,DataInputStream,pushbackInputStream,
常用的缓冲输入流有:
BufferedOutputStream,DataOutputSteam,pushbackOutputStream
9.3.5 随机存取文件
对于InputStream 和OutputStream,它们都是顺序访问流,从头至尾访问流,并且输入流只能读,不能写,输出流只能写不能读,即对一个文件不能同时进行读写。
RandomAccessFile类提供了一种称为“随机访问文件”方式,可以:对一个文件同时进行读写操作,可以在文件的任意位置进行读写操作。
主要的方法:
Public long length() :返回文件的长度
Void setLength(long newLength) :设置文件的新长度
Public void seek(long pos) :改变文件指针的位置
Public final int readInt():读入一个整数类型
Public final void writeInt(int v):写一个整数
Public long getFilePoint():获取文件指针位置
Public int skipBytes(int n):跳过n个字节
Close() 关闭文件
public class RandomFileDemo {
public static void main(String[] args) {
String fileName = "raf.txt";
RandomAccessFile raf = null;
String str1 = "this is a file.";
String str3 = "中华人民共和国";
long length, pos;
try {
// 构建对象
raf = new RandomAccessFile(fileName, "rw");
raf.writeChars(str1);
pos = raf.getFilePointer();
length = str1.length();
System.out.println("第一字符串的长度是:" + length);
// 一个字符用两个字节表示,内存中的表示和文件中的表示一致
System.out.println("写入一个字符串后,文件指针:" + pos);
// 又写入了一个字符串,重置指针位置,读取字符
System.out.println("第二个字符串");
pos = raf.getFilePointer();
// 写入字符串
raf.writeChars(str3);
raf.seek(pos);
for (int i = 0; i < str3.length(); i++) {
System.out.print(raf.readChar());
}
pos = raf.getFilePointer();
System.out.println(" 写入" + str3.length() + "字符后,文件指针:" + pos);
System.out.println("文件测试成功");
} catch (FileNotFoundException e) {
System.out.println("文件不存在");
} catch (IOException e) {
e.printStackTrace();
}
}
}
9.4 字符流处理
尽管字节流提供了处理任何数据类型的输入输出操作的功能,但它们不能直接操作Unicode字符。提供直接的字符输入输出支持是必要的。
9.4.1 Scanner 字符流
Scanner是一个可以使用正则表达式来解析基本类型和字符串的简单文本扫描器。Scanner使用分隔符模式将其输入分解为标记,默认情况下该分隔符模式与空白匹配。然后可以使用不同的next方法得到的标记转换成不同类型的值,在读取下一个标记之前可以使用hasNext方法检测一下。
public class ScannerDemo {
private static int getLineSum(String strLine) {
Scanner s = new Scanner(strLine);
int sum = 0;
while (s.hasNextInt()) {
sum += s.nextInt();
}
return sum;
}
public static void main(String[] args) {
Scanner s = null;
PrintWriter pw = null;
try {
// 从源文件输入,使用Scanner读入由空白字符分割的文本文件内容是很方便的
s = new Scanner(new File("E:/Java知识总结/test.txt"));
// 使用PrintWriter进行格式化输出
pw = new PrintWriter("E:/Java知识总结/text02.txt");
while (s.hasNextLine()) {
String strLine = s.nextLine();
// 调用方法求每一行的和
int sum = getLineSum(strLine);
// 写到文件上
pw.println(strLine + " " + sum);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
if (s != null) {
s.close();
}
if (pw != null) {
pw.close();
}
}
}
}