十、IO 文件操作(2)
1、内存操作流
操作内存流的时候(从读取出来,注意一定要把真正的数据用toByteArray或者toCharArray
将数据读出来)
之前的文件操作流是以文件的输入输出为主的,当输出的位置变成了内存,那么就称为内
存操作流。此时要使用内存流完成内存的输入和输出操作。
如果程序运行过程中要产生一些临时文件,可采用虚拟文件方式实现;
直接操作磁盘的文件很耗性能,使用内存流可以提升性能;jdk 里提供了内存流可实现类似于
内存虚拟文件的功能。
ByteArrayInputStream:将内容写到内存中 CharArrayReader
ByteArrayOutputStream:将内存中的数据写出 CharArrayWriter
ByteArrayInputStream:构造方法:
public ByteArrayInputStream(byte[] buf):全部内容
public ByteArrayInputStream(byte[] buf,int offset,int length):指定范围的内容
ByteArrayOutputStream:
public ByteArrayOutputStream()
我的总结:内存流操作:先把数据写到内存中去,然后再从内存中读取出来!提升了性能!
例子
//此处用的是内存字节流(写入加输出)
package june6D;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
public class ByteArrayDemo7 {
public static void main(String[] args) throws IOException {
String s = "java is a good language";
ByteArrayOutputStream bos = new ByteArrayOutputStream();//输
出流
bos.write(s.getBytes());
// 已经把信息写到了内存中
byte[] bys = bos.toByteArray();// 得到真正的数据
ByteArrayInputStream bis = new ByteArrayInputStream(bys);//
输入流,需要源。
byte[] b = new byte[1024];
int len;
while ((len = bis.read(b)) != -1) {
String data = new String(b, 0, len);
System.out.println(data);
}
}
}
package june6D;
import java.io.CharArrayReader;
import java.io.CharArrayWriter;
public class CharArrayDemo8 {
public static void main(String[] args) throws Exception {
// 用内存字符流先把数据保存到内存中,然后从内存中取出数据
String s = "河南城建学院";
CharArrayWriter cw = new CharArrayWriter();
cw.write(s);// 数据写到了内存中
char[] ch = cw.toCharArray();
CharArrayReader cr = new CharArrayReader(ch);
char[] b = new char[1024];
int len;
while ((len = cr.read(b)) != -1) {
String data = new String(b, 0, len);
System.out.println(data);
}
}
}
2、打印流
(只有两个,PrintWriter 和 PrintStream)
思考:如果现在要想完成一个字符串或者是 boolean 型或者是字符型的数据输出使用
OutputStream 是否方便?
肯定是不方便的,因为 OutputStream 中只能操作字节数据,所以其他的数据类型很难操作,
那么在 Java 的 IO 包中为了解决这种问题增加了两种类:PrintStream、PrintWriter。
打印流有非常好的打印功能,可以打印任何的数据类型。如,整数,小数,字符串等。
观察 PrintStream 类的构造:
public PrintStream(File file) throws FileNotFoundException
public PrintStream(OutputStream out)
虽然 PrintStream 是 OutputStream 的子类,但是在实例化的时候依然需要一个 OutputStream
的对象。
PrintWriter 和 PrintStream 都属于输出流,分别针对字符和字节。
PrintWriter 和 PrintStream 重载的 print()和 println()用于多种数据类型的输出。
print()里的参数不能为空;println()可以
PrintWriter 和 PrintStream 输出操作不抛出异常
PrintStream 调用 println 方法有自动 flush 功能;
Eg:
package june6D;
import java.io.FileWriter;
import java.io.PrintStream;
import java.io.PrintWriter;
public class PrintDemo9 {
public static void main(String[] args) throws Exception {
PrintStream ps = new PrintStream("out.txt");
// ps.write(12);
ps.println(10086);
ps.println(false);
// ps.print();针对print而言,不可以出现这样的(无参)
ps.println();// 此时就可以
//备注:System.out.println();想当于ps = System.out;
ps = System.out;
ps.println("您好!");// 控制台操作,注意上一句
// 字符打印流
PrintWriter pr = new PrintWriter("out2.txt");
// PrintWriter(OutputStream out, boolean autoFlush) 通过现有
的 OutputStream,创建新的 PrintWriter。(构造方法)
pr = new PrintWriter(new FileWriter("out2.txt"), true);// 自
动刷新,否则的话需要关闭资源!
// 与PrintStream不同,若PrintWriter使用了自动刷新方法,那么必须调用
println,print,format这些方法的其中一个才可以实现操作
pr.println("呼哈哈哈哈");
pr.println(false);
pr = new PrintWriter(System.out, true);// 打印在控制台上
pr.println(false);
pr.println("河南城建学院");
pr.println(376430645);
// pr.close();//因为使用了自动刷新。
}
}
3、格式化输出
Java5 后,PrintStream 类多了 printf()方法用于格式化输出操作。但是格式化输出的时候必须
指定输出数据的类型:
(构造方法)
PrintStream format(String fo, Object... args) 使用指定格式字符串和参数将格式化字符串
写入此输出流中。
备注:当然你也可以全部使用“%s”来表示所有的数据类型!
格式:
需要格式 % 占位符
Eg:
package july7file;
import java.io.FileWriter;
import java.io.PrintStream;
import java.io.PrintWriter;
public class Demo9 {
public static void main(String[] args) throws Exception {
PrintStream ps = new PrintStream("E:/name.txt");
ps.write("123456".getBytes());
ps.println(false);
ps.print(false);
PrintWriter pw = new PrintWriter(new
FileWriter("E:/name1.txt"),true);
pw.println("我们的未来!");//write不可以
pw = new PrintWriter(System.out,true);
pw.println("我们的未来!");//打印在控制台上
String name = "刘昭";
int age = 13;
char score = 'A';
String format = "姓名=%s,年龄=%d,成绩=%c";
System.out.printf(format,name,age,score);
int i = System.in.read();//流的重定向
System.out.println((char)i);
}
}
4、标准流
标准输入流: System.in 默认表示的是键盘录入
标准输出流: System.out 默认表示的是屏幕输出
Eg:
package june6D;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintStream;
public class SyetemDemo {
public static void main(String[] args) throws IOException {
/**
* 标准流: 标准输入流: System.in 默认表示的是键盘录入
标准输出流: System.out 默认表示的是屏幕输出
*
* 若现在我输出不想打印在屏幕上,怎么办?
* 若现在我不想通过键盘来录入数据,有怎么办?
*
* 流的重定向: static void setOut(PrintStream out) 重新分配“标准”
输出流。 static void
* setIn(InputStream in) 重新分配“标准”输入流。
*/
System.out.println("123456789");//最普通的打印
System.err.println("123652");// 同 样 是 一 种 输 出 流 , 打 印 出 的 是
123652
/**
* static void setOut(PrintStream out) 重新分配“标准”输出流。
*/
// 输出流就被重新定义到了文件,而不是屏幕
System.setOut(new PrintStream("68Demo.txt"));// 只有在定义过后
才生效,所以上面的还是会输出到控制台
System.out.println("AAAA");
System.out.println("BBBB");//就输出了在文件里
int i = System.in.read();// 接受从键盘输入的数据,写在最前面(没有
任何重新分配)才有效
System.out.println("i所对应的是:" + (char) i);// 把它转换为字符
型
System.out.println(i);
/**
* 重新分配,由标准键盘输入变为由文件输入
*/
System.setIn(new FileInputStream("copy6.4"));//备注:打印的是
文件copy6.4中的数据,而且打印在文件68Demo.txt中。
byte[] buff = new byte[1024];
int len = 0;
while ((len = System.in.read(buff)) != -1) {
System.out.println(new String(buff, 0, len));// 此时不会打
印在控制台上,因为上面已经重新定义了由打印到屏幕上转换为打印到文件里
}
}
}
5、Scanner(简单文本扫描器)
Scanner(File source) 构造一个新的 Scanner,它生成的值是从指定文件扫描的。
备注:实现了Iterable接口
package june6D;
import java.io.File;
import java.io.PrintStream;
import java.util.Scanner;
public class ScannerDemo18 {
public static void main(String[] args) throws Exception {
// 参照api
Scanner sc = new Scanner(System.in);// 从键盘输入
// int i = System.in.read();
/* 连着进行了三次,没有完成的话不停止运行
System.out.println(sc.next());
System.out.println(sc.next());
* System.out.println(sc.next());
*/
System.setOut(new PrintStream("Scanner.txt"));// 流的重定向(打
印到哪里)
sc = new Scanner(new File("copy6.4"));// 扫描位置
int line = 1;
while (sc.hasNextLine()) {// 是否有下一行 //一行一行的读取,这样的
话格式好看
System.out.println(line + " " + sc.nextLine());// 读取下一
行
line++;
}
}
}
例子:
猜数字游戏:
1. 系统随机生成一个数字[1,100];
2. 从键盘录入一个数字,[1,100]
3. 判断输入的数字和随机数比较:
随机数 > 输入数:你输入太小了
随机数 < 输入数:输入太大了
随机数 = 输入数: 恭喜哦
思考:先想怎么生成一个随机数;然后怎么在键盘中录入一个随机数,第三步就是比较了;
但是注意的是:需要确保输入的数据为数字,而且有范围的限制!
package july7file;
import java.util.Random;
import java.util.Scanner;
public class Demo12 {
public static void main(String[] args) {
guess();
}
public static void guess(){
int i = new Random().nextInt(100)+1;
System.out.println(i);
System.out.println("请输入随机数来匹配,您有五次机会!");
Scanner sc = new Scanner(System.in);//键盘录入
for (int j = 0; j < 5; j++) {
String s = sc.nextLine();
if(!s.matches("\\d+")){
System.out.println("请确认您输入的是数字");
break;
}
Integer in = new Integer(s);
if(in > 100 | in < 0){
System.out.println("请确认您输入的数字在0到100之间!");
}
switch (in.compareTo(i)) {
case 1:
System.out.println("您输入的数字过大!");
System.out.println("请输入:");
break;
case -1:
System.out.println("您输入的数字过小!");
System.out.println("请输入:");
break;
default:
System.out.println("恭喜您,您输入的数字正好匹配!");
return;
}
}
}
}
6、缓冲流
缓冲流要“套接”在相应的节点流之上,对读写的数据提供了缓冲的功能,提高了读写效率,
同时增加了一些新的方法。
四种缓冲流
BufferedReader(Reader in)
BufferedReader(Reader in,int sz)//sz 表示自定义缓冲区大小
BufferedWriter(Writer out)
BufferedWriter(Writer out,int sz)
BufferedInputStream(InputStream in)
BufferedInputStream(InputStream in,int sz)
BufferedOutputStream(OutputStream out)
BufferedOutputStream(OutputStream out,int sz)
BufferedReader 提供 readLine 方法用于读取一行字符串。
BufferedWriter 提供了 newLine 方法用于写入一个行分隔符。等价于//.writer("\r\n");
对于输出的缓冲流,写出的数据会先在内存中缓冲,使用 flush 方法将会使内存中的数据立
刻写出。
Eg:
package june6D;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
//用缓冲流,性能相对高些
public class BufferedInputStreamDemo22 {
public static void main(String[] args) throws IOException {
/*
* BufferedInputStream bis = new BufferedInputStream(new
* FileInputStream("68.txt")); BufferedOutputStream bos = new
* BufferedOutputStream(new FileOutputStream("buffer.txt"));
*
* int len = 0;
* while((len = bis.read()) != -1){
* bos.write(len);
* }
* bos.close();
* bis.close();
*/
try (
BufferedReader br = new BufferedReader(new FileReader("68.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter(
"bufferWriter.txt")))
{//java7新特性,自动关闭资源
String Line = null;
while ((Line = br.readLine()) != null) {
bw.write(Line);
bw.newLine();//此时必须加上换行操作,注意这是个新用法(方法)
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
我的总结:在后续的学习中,缓冲流用到的会很多,因为效率高!
7、合并流(SequenceInputStream)
需要两个源文件,还有输出的目标文件
SequenceInputStream:
将两个文件的内容合并成一个文件
该类提供的方法:
SequenceInputStream(InputStream s1, InputStream s2) :根据两个字节输入流对象来创建合并
流对象。
备注:谁放在前面,谁就先打印出来
Eg:
package june6D;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.SequenceInputStream;
//和并两个文件的合并流
public class SequenceInputStreamDemo24 {
public static void main(String[] args) throws IOException {
SequenceInputStream si = new SequenceInputStream(
new FileInputStream("6.4"),
new FileInputStream("hello.java"));
OutputStream os = new FileOutputStream("sequence.txt");
int len;
byte []b = new byte[1024];
while((len = si.read(b)) != -1){
os.write(b, 0, len);
}
}
}