数据输入流和数据输出流
数据输入流: DataInputStream
数据输出流: DataOutputStream
可以写基本数据类型也可以读基本数据类型。
怎么写的就怎么读,顺序不可以打乱。
内存操作流
此流不直接关联任何文件,只在内存中进行读写,
操作字节数组
ByteArrayOutputStream:在内存中维护了一个字节数组,作为缓冲区,随着数据的不断写入,缓冲区不断的扩充。可使用 toByteArray () 和 toString () 获取缓冲区中的数据。此类实现了一个输出流,其中的数据被写入一个byte数组。
ByteArrayInputStream
此流关闭无效,所以无需关闭
操作字符数组:维护了一个字符数组作为缓冲区
CharArrayWrite
CharArrayReader
操作字符串
StringWriter
StringReader
package com.itheima.demo19;
import java.io.CharArrayWriter;
import java.io.IOException;
public class Test3 {
public static void main(String[] args) throws IOException {
CharArrayWriter writer = new CharArrayWriter();
writer.write("rewtvf");
writer.write(new char[]{'a','s','d','w'});
//System.out.println(writer);//rewtvfasdw
char[] chars = writer.toCharArray();
// System.out.println(chars);//rewtvfasdw
String s = String.valueOf(chars);
//System.out.println(s);//rewtvfasdw
System.out.println(writer.toString());//rewtvfasdw
}
}
package com.itheima.demo19;
import java.io.*;
import java.util.ArrayList;
public class Tes4 {
public static void main(String[] args) throws IOException {
FileInputStream fis1 = new FileInputStream(new File("E:\\mp3\\曾经的你.mp3"));//FileInputStream 用于读取诸如图像数据之类的原始字节流。要读取字符流,请考虑使用 FileReader
FileInputStream fis2 = new FileInputStream(new File("E:\\mp3\\蓝莲花.mp3"));
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ArrayList<FileInputStream> arrayList = new ArrayList<>();//定义数组,用来存放这两个读到的字节流
arrayList.add(fis1);
arrayList.add(fis2);
for (FileInputStream stream : arrayList) {//遍历数组,也就是遍历数组中的字节。
byte[] bytes1 = new byte[1024 * 8];
int len1 = 0;
while ((len1 = stream.read(bytes1)) != -1) {//开始循环写入缓冲区
bos.write(bytes1, 0, len1);
}
stream.close();
}
byte[] bytes = bos.toByteArray();//获取缓冲区中的数据
ByteArrayInputStream bis = new ByteArrayInputStream(bytes);//将获取到的数据读入这个缓冲区中
FileOutputStream fos = new FileOutputStream(new File("E:\\mp3\\demo2.mp3"));
byte[] bytes2 = new byte[1024 * 8];
int len2 = 0;
while ((len2 = bis.read(bytes2)) != -1) {
fos.write(bytes2, 0, len2);
}
System.out.println("合并完毕");
fos.close();
}
}
package com.itheima.demo18;
import java.io.*;
import java.util.ArrayList;
//将两首歌合并为一首歌,
//分析:用FileInputStream分别读取两首歌,遍历数组,将遍历到的字节数存进数组中
//读出来,用FileOutputStream写进新的文件里面
public class Test12 {
public static void main(String[] args) throws IOException {
FileInputStream in1 = new FileInputStream("E:\\mp3\\曾经的你.mp3");
FileInputStream in2 = new FileInputStream("E:\\mp3\\蓝莲花.mp3");
FileOutputStream out = new FileOutputStream("E:\\mp3\\demo1.mp3");
byte[] bytes = new byte[1024 * 8];
int len = 0;
ArrayList<FileInputStream> list = new ArrayList<>();
list.add(in1);
list.add(in2);
for(FileInputStream in : list) {
while ((len = in.read(bytes))!=-1){
out.write(bytes,0,len);
out.flush();
}
in.close();
}
System.out.println("复制完成");
out.close();
}
}
打印流
-
打印流只能操作目的地,不能操作数据源,(不能进行读取数据)不是成对出现的,是单个的。
-
可以操作任意数据类型的数据,调用print()方法可以写任意数据类型
-
如果我们启用自动刷新,那么在调用println、printf 或 format 方法中的一个方法的时候,会完成自动刷新
-
通过以下构造创建对象 能够启动自动刷新 然后调用println、printf 或 format 方法中的一个方法的时候,会完成自动刷新
public PrintWriter(OutputStream out, boolean autoFlush) 启动 自动刷新
public PrintWriter(Writer out, boolean autoFlush) 启动自动刷新
-
这个流可以直接对文件进行操作(可以直接操作文件的流: 就是构造方法的参数可以传递文件或者文件路径)
字节打印流 PrintStream,为其他输出流添加了功能,使他们能够方便额的打印各种数据表示形式。
字符打印流 PrintWriter
out 标准输出流,此流已经打开并且准备接受输出数据,通常,此流对应于显示器输出或者由主机环境或用户指定的另一个输出目标,对于简单独立的java应用程序,编写一行输出数据的典型方式是System.out.println();
PrintWriter实现自动刷新和换行
PrintWriter pw = new PrintWriter(new FileWriter("printWriter2.txt") , true) ;
pw.println(true) ;
pw.println(100) ;
pw.println("中国") ;
package com.itheima.demo19;
import java.io.*;
//打印流复制文本文件
public class Test5 {
public static void main(String[] args) throws IOException {
PrintWriter pw = new PrintWriter(new FileWriter("f.txt"));
BufferedReader br = new BufferedReader(new FileReader("student.txt"));
while (true) {
String s = br.readLine();
if(s!=null) {
pw.println(s);
}else{
break;
}
}
br.close();
pw.close();
}
}
标准输入输出流
Scanner(File source)
构造一个新的 Scanner,它生成的值是从指定文件扫描的。
Scanner(InputStream source)
构造一个新的 Scanner,它生成的值是从指定的输入流扫描的。
在System这个类中存在两个静态的成员变量:
public static final InputStream in: 标准输入流, 对应的设备是键盘
public static final PrintStream out: 标准输出流 , 对应的设备就是显示器
System.in的类型是InputStream.
System.out的类型是PrintStream是OutputStream的孙子类FilterOutputStream 的子类.
二种方式实现键盘录入
1.Scanner
2.BufferedReader的readLine方法。
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
输出语句用字符缓冲流改进
获取System下的in成员变量
InputStream in = System.in ;
in是一个字节输入流对象,那么我们就可以通过这个字节输入流对象进行读取键盘录入的数据.
那么我们既然要读取数据,之前我们讲解了两种读取数据的方式:
1. 一次读取一个字节
2. 一次读取一个字节数组
那么我们在这个地方使用那种读取方式. 经过分析,这两种读取方式都不太合适.因为数据是客户通过键盘录入进来的,而我们希望直接读取一行数据. 而既然要读取一行数据,那么我们就需要使用readLine方法,而这个方法是属于BufferedReader的方法,而我们就需要创建一个BufferedReader对象进行读取数据.而我们这in有属于字节流,而创建BufferedReader对象的时候需要一个字符流,而我们就需要将这个字节流转换成字符流,那么既然要对其进行转换,那么就需要使用转换流. 需要使用InputStreamReader.
package com.itheima.demo19;
import java.io.*;
import java.util.Scanner;
public class Test6 {
public static void main(String[] args) throws IOException {
//Scanner sc = new Scanner(System.in);第一种方式实现键盘的录入
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
while (true) {
System.out.println("请输入数据");
String s = br.readLine();
System.out.println(s);
}
}
}
随机访问流RandomAccessFile
概述:RandomAccessFile最大的特点就是能读能写
RandomAccessFile类不属于流,是object类的子类,但是它融合了InputStream和OutputStream的功能。支持对随机访问文件的读取和写入。
RandomAccessFile的父类是Object , 这个流对象可以用来读取数据也可以用来写数据.可以操作任意数据类型的数据.我们可以通过getFilePointer方法获取文件指针,并且可以通过seek方法设置文件指针
package com.itheima.demo19;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
//把一个文本文件复制5分
public class Test {
public static void main(String[] args) throws IOException {
for (int i = 1; i <=5; i++) {
RandomAccessFile read = new RandomAccessFile(new File("C:\\Users\\Administrator\\Desktop\\a.txt"), "rw");
File file = new File("C:\\Users\\Administrator\\Desktop\\a-副本"+i+".txt");
RandomAccessFile write = new RandomAccessFile(file, "rw");
int len = 0;
byte[] bytes = new byte[1024*8];
while ((len = read.read(bytes)) != -1) {
write.write(bytes, 0, len);
}
}
System.out.println("复制完成");
}
}
序列化流和反序列化流
序列化流
就是把对象通过流的方式存储到文件中.注意:此对象 要重写Serializable 接口才能被序列化。ObjectOutputStream
反序列化流
ObjectInputStream
就是把文件中存储的对象以流的方式还原成对象
像这样一个接口中如果没有方法,那么这样的接口我们将其称之为标记接口(用来给类打标记的,相当于猪肉身上盖个章) 一个对象可以被序列化的前提是这个对象对应的类必须实现Serializable接口
如何解决序列化时候的黄色警告线问题
-
我们的一个类可以被序列化的前提是需要这个类实现Serializable接口,就需要给这个类添加一个标记. 在完成序列化以后,序列化文件中还存在一个标记,然后在进行反序列化的时候, 会验证这个标记和序列化前的标记是否一致,如果一致就正常进行反序列化,如果不一致就报错了. 而现在我们把这个类做了修改,将相当于更改了标记,而导致这两个标记不一致,就报错了. 解决问题: 只要让这个两个标记一致,就不会报错了吧 alt+enter, 生成出来 private static final long serialVersionUID = -7602640005373026150L;
如何让对象的成员变量不被序列化
使用transient关键字声明不需要序列化的成员变量
private transient int age ;// 可以阻止成员变量的序列化使用transient
package com.itheima.demo19;
import java.io.*;
public class Test9 {
public static void main(String[] args) throws IOException, ClassNotFoundException {
//write();
read();
}
private static void read() throws IOException, ClassNotFoundException {
ObjectInputStream oip = new ObjectInputStream(new FileInputStream("aa.txt"));
Student S = (Student) oip.readObject();
System.out.println(S.getName() + "===" + S.getAge());
}
/* private static void write() throws IOException {
ObjectOutputStream oop = new ObjectOutputStream(new FileOutputStream("aa.txt"));
Student st = new Student("cherry", 21);
oop.writeObject(st);
oop.close();
}*/
}
package com.itheima.demo19;
import java.io.Serializable;
public class Student implements Serializable {
private static final long serialVersionUID = -7476321121279308524L;
private String name;
// transient 可以排除某些属性,不要被序列化。
//private transient int age;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
Properties(键和值默认为string类型)
概述:该类表示了一个持久的属性集。可保存在流中或在流中加载。属性列表中每个键及其对应值都是一个字符串。此类的父类是Hashtable
属于双列集合,这个集合中的键和值都是字符串。Properties不能指定泛型
Properties的特殊功能
public Object setProperty(String key,String value)
调用 Hashtable 的方法 put,给其重新放值
public String getProperty(String key)
用指定的键在此属性列表中搜索属性。
public Set<String> stringPropertyNames()
返回此列表属性的键集
Properties的load()和store()功能
public void load(Reader reader):
读取键值对数据把数据存储到Properties中
public void store(Writer writer, String comments)
把Properties集合中的键值对数据写入到文件中, comments注释
判断文件中是否有指定的键如果有就修改值的
package com.itheima.demo18;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;
import java.util.Set;
public class Test13 {
public static void main(String[] args) throws IOException {
/*我有一个文本文件,我知道数据是键值对形式的,但是不知道内容是什么。
请写一个程序判断是否有“lisi”这样的键存在,如果有就改变其值为”100”
分析:
- a: 把文本文件中的数据加载到Properties集合中
- b: 判断这个集合中是否有"lisi"这个键
- 如果有直接修改其值为100
- c: 把集合中的数据再次存储到文本文件中*/
Properties p = new Properties();
FileReader reader = new FileReader("a.txt");
p.load(reader);//从输入流中读取指定的键和值
Set<String> stringSet = p.stringPropertyNames();//返回此列表属性的键集
for (String s : stringSet) {//遍历键集,找到lisi
if ("lisi".equals(s)) {
p.setProperty(s, "100");// 调用 Hashtable 的方法 put,给其重新放值
break;
}
}
FileWriter writer = new FileWriter("a.txt");//定义一个新文件
p.store(writer, null);//此 Properties 表中的属性列表(键和元素对)写入输出流。
reader.close();
writer.close();
}
}
SequenceInputStream
SequenceInputStream
表示其他输入流的逻辑串联。
它从输入流的有序集合开始,并从第一个输入流开始读取,直到到达文件末尾,接着从第二个输入流读取,依次类推,直到到达包含的最后一个输入流的文件末尾为止
构造方法
SequenceInputStream(InputStream s1, InputStream s2)
通过记住这两个参数来初始化新创建的 SequenceInputStream(将按顺序读取这两个参数,先读取 s1,然后读取 s2),以提供从此 SequenceInputStream 读取的字节。
构造方法
SequenceInputStream(Enumeration<? extends InputStream> e)
通过记住参数来初始化新创建的 SequenceInputStream,该参数必须是生成运行时类型为 InputStream 对象的 Enumeration 型参数。
package com.itheima.demo1;
import javax.swing.*;
import java.io.*;
import java.util.ArrayList;
public class Test6 {
public static void main(String[] args) throws IOException {
/* 3.比如我有一个 a.mp3 大小是 4.2M 把想把这个a.mp3 拆成1M一份 能拆5个小文件,当然最后一个是 0.2M;
//然后你在把这个5个小文件再合并成一个大文件,然后把5个零碎的文件删掉。*/
/* RandomAccessFile rr = new RandomAccessFile("黄昏.mp3","rw");
int len = 0;
int i =0;
byte[] bytes = new byte[1024 * 1024];
RandomAccessFile rw = null;
while ((len= rr.read(bytes))!=-1){
i++;
String filename = "黄昏"+i+".mp3";
rw = new RandomAccessFile(filename, "rw");
rw.write(bytes,0,len);
}
rw.close();
rr.close();
System.out.println("分割完毕");
*/
ArrayList<FileInputStream> arrayList = new ArrayList<>();
File file = new File("黄昏.mp3");
File[] files = file.listFiles();
for (File file1 : files) {
FileInputStream fileInputStream = new FileInputStream(file1);
arrayList.add(fileInputStream);
}
int i1 = 0;
SequenceInputStream sqi1 = new SequenceInputStream(arrayList.get(i1), arrayList.get(i1 + 1));
SequenceInputStream sqi2 = new SequenceInputStream(sqi1, arrayList.get(i1 + 2));
SequenceInputStream sqi3 = new SequenceInputStream(sqi2, arrayList.get(i1 + 3));
SequenceInputStream sqi4 = new SequenceInputStream(sqi3, arrayList.get(i1 + 4));
SequenceInputStream sqi5 = new SequenceInputStream(sqi4, arrayList.get(i1 + 5));
FileOutputStream fop = new FileOutputStream("黄昏副本.mp3");
int len1 = 0;
byte[] bytes1 = new byte[256];
while ((len1 = sqi5.read(bytes1))!=-1){
fop.write(bytes1,0,len1);
fop.flush();
}
sqi1.close();
sqi2.close();
sqi3.close();
sqi4.close();
sqi5.close();
fop.close();
for (File file1 : files) {
file1.delete();
}
}
}
//第二种方法
package com.itheima.demo1;
import java.io.*;
import java.util.Enumeration;
import java.util.Vector;
public class Test8 {
public static void main(String[] args) throws IOException {
// fenGe();
heBing();
}
private static void heBing() throws IOException {
Vector<FileInputStream> vector = new Vector<>();
for (int i = 1; i <= 6; i++) {
FileInputStream in = new FileInputStream(i+".mp3");
vector.add(in);
}
Enumeration<FileInputStream> elements = vector.elements();
SequenceInputStream allIn = new SequenceInputStream(elements);
FileOutputStream out = new FileOutputStream("黄昏a.mp3");
int len = 0;
byte[] bytes = new byte[1024];
while ((len = allIn.read(bytes)) != -1) {
out.write(bytes, 0, len);
out.flush();
}
allIn.close();
out.close();
}
/*private static void fenGe() throws IOException, FileNotFoundException {
RandomAccessFile in = new RandomAccessFile("黄昏.mp3","rw");
for (int i = 1; i <= 5; i++) {
String s = i + ".mp3";
RandomAccessFile out = new RandomAccessFile(s,"rw");
byte[] bytes = new byte[1024*1024];
in.read(bytes);
out.write(bytes,0,1024*1024);
in.seek(in.getFilePointer());
}
RandomAccessFile out = new RandomAccessFile("6.mp3","rw");
int len = 0;
byte[] bytes = new byte[1024];
while ((len = in.read(bytes))!=-1){
out.write(bytes,0,len);
}
System.out.println("分割完毕");
}*/
}