目录
一、序列流
序列流可以把多个字节输入流整合成一个,
它从一个有序的输入流集合开始,从第一个读取到文件的结尾,然后从第二个文件读取,
依此类推,直到最后一个输入流达到文件的结尾。
其整合两个输入流的方式如下,
SequenceInputStream(InputStream s1, InputStream s2)
我们来看看具体如何使用的吧,
//将两个文件的内容合并写到一个文本文件中
FileInputStream fis1=new FileInputStream("data.txt");
FileInputStream fis2=new FileInputStream("data2.txt");
SequenceInputStream sis=new SequenceInputStream(fis1,fis2);
FileOutputStream fos=new FileOutputStream("dataOutput.txt");
int c;
while((c=sis.read())!=-1){
fos.write(c);
}
sis.close();
fos.close();
二、内存输出流
2.1内存输出流概述与使用
该输出流可以向内存中写数据,把内存当作一个缓冲区, 写出之后可以一次获取所有的数据,
在使用时会创建对象ByteArrayOutputStream,该类中的数据被写入了一个byte数组,缓冲区会随着数据的写入而自动增长,
写出数据为write(int)或者write(byte[]),获取数据为toByteArray(),
之前我们使用FileInputStream读取中文的时候出现了乱码问题,这个问题我们也可以用内存输出流来解决,
FileInputStream fis=new FileInputStream("data.txt");
ByteArrayOutputStream baos=new ByteArrayOutputStream();//在内存中创建了字节数组缓冲区
int b;
while((b=fis.read())!=-1){
baos.write(b);//将文件数据写入缓冲区
}
byte arr[]=baos.toByteArray();//将缓冲区数据获取到字节数组中
System.out.println(new String(arr));
fis.close();
//注意这里不用关闭ByteArrayOutputStream的流,该流关闭操作无效
我们可以看到中文读取的时候已经可以正确显示了,
2.2内存输出流之面试题
要求定义一个文件输出流,调用read(byte b[])的方法,将data.txt文件中的内容打印出来(byte数组大小限制为5)。
FileInputStream fis=new FileInputStream("data.txt");
ByteArrayOutputStream baos=new ByteArrayOutputStream();
byte arr[]=new byte[5];
int len;
while((len=fis.read(arr))!=-1){
baos.write(arr,0,len);//将文件数据写入缓冲区
}
System.out.println(baos);
fis.close();
三、随机访问流
RandomAccessFile类不属于流,是Object类的子类,但它融合了InputStream和OutputStream的功能,
支持对随机访问文件的读取和写入,该类有两个构造函数,
RandomAccessFile(File file, String mode)//创建File文件的随机访问文件流,用于读取和写入
RandomAccessFile(String name, String mode)创建指定名称name的随机访问文件流,用于读取和写入
//其中mode包括:"r",只读、"rw"读取和写入、"rws"读取和写入并且同步更新
RandomAccessFile raf=new RandomAccessFile("data.txt","rw");
System.out.println(raf.readLine());
raf.seek(20);//将指针移到索引为20的地方
raf.write("You love java.".getBytes());//写入字符串
raf.close();
在指定位置进行读写的好处是可以进行多线程的下载,可以将整个文件按照一定字节数分块,
然后分块用多线程下载最后将字节写到对应的位置就可以了。
四、对象操作流
4.1对象操作流概述与使用
ObjectInputStream和ObjectOutputStream是操作对象进行读取和写入的,
主要用到的方法是writeObject和readObject,我们来看看具体如何使用,
Student s1=new Student("测试1",21);
Student s2=new Student("测试2",22);
ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("StudentData.txt"));
oos.writeObject(s1);
oos.writeObject(s2);
oos.close();
ObjectInputStream ois=new ObjectInputStream(new FileInputStream("StudentData.txt"));
Student stu1=(Student)ois.readObject();
Student stu2=(Student)ois.readObject();
System.out.println(stu1);
System.out.println(stu2);
ois.close();
需要注意的是我们要在自定义的类对象中实现一下Serializable接口,实现序列化,否则会抛出NotSerializableException异常,
class Student implements Serializable
然后我们看看写入对象数据然后紧接着读取输出的结果,
4.2利用集合进行对象读写优化
我们发现,如果自定义对象比较多,那么存储的时候就会比较麻烦,
一般这个时候我们会先将自定义的对象装到集合对象里面,然后将集合对象写入到文件中,
Student s1=new Student("测试1",21);
Student s2=new Student("测试2",22);
Student s3=new Student("测试3",23);
ArrayList<Student> list=new ArrayList<>();
list.add(s1);
list.add(s2);
list.add(s3);
ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("StudentData.txt"));
oos.writeObject(list);
oos.close();
ObjectInputStream ois=new ObjectInputStream(new FileInputStream("StudentData.txt"));
ArrayList<Student> readlist=(ArrayList<Student>)ois.readObject();
for (Student stu: readlist) {
System.out.println(stu);
}
ois.close();
五、数据输入输出流
DataInputStream和DataOutputStream可以按照基本数据类型大小读写数据,
例如按照Long类型大小写出一个数字,写出时该数据占8个字节,读取的时候也按照Long类型读取,一次读取8个字节,
DataOutputStream dos=new DataOutputStream(new FileOutputStream("data.txt"));
dos.writeInt(10086);
dos.writeBytes("java");
dos.writeChar(97);
dos.close();
DataInputStream dis=new DataInputStream((new FileInputStream("data.txt")));
System.out.println(dis.readInt());
byte arr[]=new byte[4];
dis.readFully(arr);
for (int i = 0; i < 4; i++) {
System.out.print((char)arr[i]);
}
System.out.println();
System.out.println(dis.readChar());
dis.close();
六、打印流
打印流可以很方便的将对象的toString()结果输出,并且自动加上换行,而且可以使用自动刷出的模式,
System.out就是一个PrintStream,默认向控制台输出信息,PrintStream是打印字节流,PrintWriter是打印字符流。
PrintStream ps=System.out;
ps.println(100);//底层通过Integer.toString()将100转换为字符串输出
ps.println("java");
Student stu=new Student("测试",20);//打印引用数据类型,使用toString()方法(如果为null则打印null)
ps.println(stu);
我们还可以使用PrintWriter将字符流写入文件,
PrintWriter pw=new PrintWriter("data.txt");
pw.println(97);//写数字97
pw.write(97);//写字符a
pw.close();
其中PrintWriter的构造函数有个autoFlush需要注意,
PrintWriter(OutputStream out, boolean autoFlush)//这里的autoFlush如果设置为true,那么边写入的时候会自动刷新内容到文件中,自动刷新只针对println操作,对write和print无效。
七、标准输入输出流
7.1标准输入输出流概述与使用
- System.in是InputStream,标准输入流,默认可以从键盘读取字节数据
- System.out是OutputStream,标准输出流,默认可以向控制台中输出字符和字节数据
正常使用标准输入输出流时不用执行close操作,但是如果关联到某个文件上了,则必须执行close操作,
InputStream is=System.in;
int x=is.read();//读取一个字节的数据
System.out.println(x);
is.close();
7.2修改标准输入输出流读写文件数据
我们还可以使用System.setIn和System.setOut方法改变标准输入流,从文件读取写入数据,
System.setIn(new FileInputStream("data.txt"));//改变标准输入流
System.setOut(new PrintStream("dataOutput.txt"));//改变标准输出流
InputStream is=System.in;//获取标准的键盘输入流,默认指向键盘,改变后指向文件
PrintStream ps=System.out;//获取标准的打印输出流,默认指向控制台,改变后指向文件
int b;
while((b=is.read())!=-1){
ps.write((char)b);
}
is.close();
ps.close();
7.3修改标准输入输出流拷贝图片
拷贝图片其实和前面一个差不多,只不过一个是文本文件,一个是图片文件。这里我们用byte数组来读效率高一点,
System.setIn(new FileInputStream("luffy.jpg"));//改变标准输入流
System.setOut(new PrintStream("luffyCopy.jpg"));//改变标准输出流
InputStream is=System.in;//获取标准的键盘输入流,默认指向键盘,改变后指向文件
PrintStream ps=System.out;//获取标准的打印输出流,默认指向控制台,改变后指向文件
byte arr[]=new byte[1024];
int len;
while((len=is.read(arr))!=-1){
ps.write(arr,0,len);
}
is.close();
ps.close();
可以看到图片被复制成功了,
八、两种方式的键盘录入
8.1 BufferedReader
BufferedReader可以通过InputStreamReader将字节流的System.in转换为字符流,
然后构造出BufferedReader对象进行键盘录入,
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
String str=br.readLine();
System.out.println(str);
br.close();
8.2 Scanner
Scanner读取键盘录入的功能更加强大,不仅可以读取字符串,还有其他基本类型数据。
Scanner sc=new Scanner(System.in);
String str=sc.nextLine();
System.out.println(str);
sc.close();
九、Properties
9.1 Properties概述及基本使用
Properties类主要用于读取Java的配置文件,
不同的编程语言有自己所支持的配置文件,配置文件中很多变量是经常改变的,
为了方便用户的配置,能让用户够脱离程序本身去修改相关的变量设置。
就像在Java中,其配置文件常为.properties文件,是以键值对的形式进行参数配置的,
它是Hashtable的子类,我们先用集合的方法来存储键值对元素,
Properties prop=new Properties();
prop.put("test",1);//使用集合的方法存储
System.out.println(prop);
Properties类表示了一个持久的属性集,可以保存在流中或者从流中加载,
其属性列表中每个键对应的值都是一个字符串。
9.2 Properties特殊功能
public Object setProperty(String key,String value)//设置键值对
public String getProperty(String key)//根据键返回值
public Enumeration<String> stringPropertyNames()//返回属性列表中所有键的枚举
我们来看看实际如何使用这些方法,
Properties prop=new Properties();
prop.setProperty("name","peru");
prop.setProperty("home","wuhan");
prop.setProperty("tel","15912345678");
Enumeration<String> en=(Enumeration<String>)prop.propertyNames();//获取所有键
while(en.hasMoreElements()){
String key=en.nextElement();//获取键
String value=prop.getProperty(key);//根据键获取值
System.out.println(key+"="+value);
}
9.3 配置文件的加载和保存
我们现在想要将配置文件存储在硬盘上,而不是内存中,这里就需要用到Properties的load()和store()方法了,
void load(InputStream inStream)//从输入字节流读取属性列表(键和元素对)
void load(Reader reader)//从输入字符流读取属性列表(键和元素对)
void store(OutputStream out, String comments)//将此属性列表(键和元素对)写入此Properties表中,以适合于使用load(InputStream)方法加载到Properties表中的格式输出流
void store(Writer writer, String comments)//将此属性列表(键和元素对)写入此Properties表中,以适合使用load(Reader)方法的格式输出到输出字符流
我们来看看具体如何使用这两个方法,
Properties prop=new Properties();
//读取配置文件
prop.load(new FileInputStream("config.properties"));
System.out.println(prop);
//修改配置文件
prop.setProperty("home","beijing");
prop.store(new FileOutputStream("config.properties"),"修改了家庭住址");//后面的参数comments为对配置文件的说明
我们可以先看到配置文件被正确读取出来了,
然后打开配置文件发现也被正确修改了信息,而且comments的信息也在文件中以注释的形式体现了,
如果什么也不想显示可以给comments赋值为null,同时显示的还有更改的时间,