杂七杂八的流
数据输入输出流的概述和使用
-
数据输入输出流的概述
数据输入流: DataInputStream
数据输出流: DataOutputStream
特点: 可以写基本数据类型,可以读取基本数据类型
public static void main(String[] args) throws IOException {
//数据输入输出流:这对流的特点是,能够读写基本数据类型。
// DataOutputStream
// DataInputStream
//writeData();
//你怎么写的,你怎么读,顺序不要乱
DataInputStream in = new DataInputStream(new FileInputStream("a.txt"));
int i = in.readInt();
System.out.println(i);
double v = in.readDouble();
System.out.println(v);
boolean b = in.readBoolean();
System.out.println(b);
String s = in.readUTF();
System.out.println(s);
}
private static void writeData() throws IOException {
DataOutputStream out = new DataOutputStream(new FileOutputStream("a.txt"));
out.writeInt(100);
out.writeDouble(3.14);
out.writeBoolean(true);
out.writeUTF("你好世界");
out.close();
}
内存操作流的概述和使用
-
内存操作流的概述
操作字节数组
ByteArrayOutputStream
ByteArrayInputStream
此流关闭无效,所以无需关闭
操作字符数组
CharArrayWrite
CharArrayReader
操作字符串
StringWriter
StringReader -
构造方法: public ByteArrayOutputStream()
public static void main(String[] args) throws IOException {
//内存操作流:此流不直接关联任何文件,只在内存中进行读写。
//ByteArrayOutputStream 他在内存中维护了一个字节数组,作为缓冲区,随着数据的不断写入,缓冲区会不断的扩充。
//可使用 toByteArray () 和 toString () 获取缓冲区中的数据。
/* 此类实现了一个输出流,其中的数据被写入一个 byte 数组。
缓冲区会随着数据的不断写入而自动增长。可使用 toByteArray () 和 toString () 获取数据。
关闭 ByteArrayOutputStream 无效。*/
//ByteArrayInputStream
ByteArrayOutputStream out = new ByteArrayOutputStream();
out.write("爱生活".getBytes());
out.write("爱java".getBytes());
out.write("好好学习".getBytes());
out.write("天天向上".getBytes());
out.write("天天向上".getBytes());
//toByteArray(); 取出ByteArrayOutputStream所维护的那个字节数组
byte[] bytes = out.toByteArray();
String s = new String(bytes);
System.out.println(s);
String s1 = out.toString();
System.out.println(s1);
out.close();
System.out.println("===================================");
/* ByteArrayInputStream( byte[] buf)
创建一个 ByteArrayInputStream,使用 buf 作为其缓冲区数组。*/
//byte[] bytes1 = new byte[1024];
ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
byte[] bytes1 = new byte[1024];
int len = bis.read(bytes1);
String s2 = new String(bytes1, 0, len);
System.out.println(s2);
}
public static void main(String[] args) throws IOException {
/* b:
操作字符数组 他维护了一个字符数组作为缓冲区
CharArrayWrite
CharArrayReader
c:
操作字符串
StringWriter
StringReader*/
CharArrayWriter charArrayWriter = new CharArrayWriter();
charArrayWriter.write("一行字符串");
charArrayWriter.write(new char[]{'a','b','c'});
char[] chars = charArrayWriter.toCharArray();
System.out.println(String.valueOf(chars));
System.out.println(charArrayWriter.toString());
System.out.println("===============================");
//StringWriter
StringWriter stringWriter = new StringWriter();
stringWriter.write("abc");
stringWriter.write("abc");
stringWriter.write("abc");
stringWriter.write("abc");
System.out.println(stringWriter.toString());
}
打印流的概述和特点以及作为Writer的子类使用
打印流的特点
打印流只能操作目的地,不能操作数据源(不能进行读取数据)
可以操作任意数据类型的数据 调用print() 方法可以写任意数据类型
如果我们启用自动刷新,那么在调用println、printf 或 format 方法中的一个方法的时候,会完成自动刷新
- 通过以下构造创建对象 能够启动自动刷新 然后调用println、printf 或 format 方法中的一个方法的时候,会完成自动刷新
public PrintWriter(OutputStream out, boolean autoFlush) 启动 自动刷新
public PrintWriter(Writer out, boolean autoFlush) 启动自动刷新
- 这个流可以直接对文件进行操作(可以直接操作文件的流: 就是构造方法的参数可以传递文件或者文件路径)
public static void main(String[] args) throws IOException {
//打印流:只能写出数据,不能读取数据,单个的,不是成对。
//字节打印流 PrintStream
//字符打印流 PrintWriter
//PrintStream 为其他输出流添加了功能,使它们能够方便地打印各种数据值表示形式。
/* PrintStream(File file)
创建具有指定文件且不带自动行刷新的新打印流。
PrintStream(OutputStream out, boolean autoFlush)
创建新的打印流。
*/
PrintStream stream = new PrintStream("a.txt");
stream.write("你好".getBytes());
stream.println("我很好");
stream.flush();
stream.println("我很好");
stream.println("我很好");
/*
out 标准”输出流。此流已打开并准备接受输出数据。通常,此流对应于显示器输出或者由主机环境或用户指定的另一个输出目标。
对于简单独立的 Java 应用程序,编写一行输出数据的典型方式是:
System.out.println(data)*/
PrintStream out = System.out;
out.write("hhhe".getBytes());
System.out.println("abc");
System.out.write("ab".getBytes());
}
PrintWriter实现自动刷新和换行
PrintWriter pw = new PrintWriter(new FileWriter(“printWriter2.txt”) , true) ;
pw.println(true) ;
pw.println(100) ;
pw.println(“中国”) ;
打印流复制文本文件
分析:
-
这个打印流只能进行写数据,不能进行读取数据,
那么我们应该找一个可以读取文本文件中的的数据的流对象进行读取操作. -
而我们非常喜欢高效的流对象,于是我们可以使用BufferedReader进行读取数据.
public static void main(String[] args) throws IOException {
PrintWriter printWriter = new PrintWriter(new FileOutputStream("C:\\Users\\ShenMouMou\\Desktop\\a.java"),true);
BufferedReader in = new BufferedReader(new FileReader("MyTest1.java"));
while (true){
String s = in.readLine();
if(s!=null){
printWriter.println(s);
}else{
break;
}
}
in.close();
printWriter.close();
}
标准输入输出流概述和输出语句的本质
- 标准输入输出流概述
在System这个类中存在两个静态的成员变量:
public static final InputStream in: 标准输入流, 对应的设备是键盘
public static final PrintStream out: 标准输出流 , 对应的设备就是显示器
System.in的类型是InputStream.
System.out的类型是PrintStream是OutputStream的孙子类FilterOutputStream 的子类.
public static void main(String[] args) throws FileNotFoundException {
/*
Scanner(File source)
构造一个新的 Scanner,它生成的值是从指定文件扫描的。
Scanner(InputStream source)
构造一个新的 Scanner,它生成的值是从指定的输入流扫描的。*/
Scanner scanner = new Scanner(new File("MyTest1.java"));
while (scanner.hasNextLine()){
String s = scanner.nextLine();
System.out.println(s);
}
Scanner scanner1 = new Scanner(new FileInputStream("MyTest1.java"));
}
二种方式实现键盘录入
public static void main(String[] args) throws IOException {
// Scanner scanner = new Scanner(System.in);
//键盘录入的 第二种方式
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
while (true){
System.out.println("请输入数据");
String s = reader.readLine();
System.out.println(s);
if("886".equals(s)){
break;
}
}
}
随机访问流概述和写出数据
-
随机访问流概述
RandomAccessFile概述 最大特点 能读能写
RandomAccessFile类不属于流,是Object类的子类。但它融合InputStreamOutputStream的功能。
支持对随机访问文件的读取和写入。 -
RandomAccessFile的父类是Object , 这个流对象可以用来读取数据也可以用来写数据.可以操作任意数据类型的数据.
我们可以通过getFilePointer方法获取文件指针,并且可以通过seek方法设置文件指针
public static void main(String[] args) throws IOException {
/* A:
随机访问流概述
RandomAccessFile概述 最大特点 能读能写
RandomAccessFile类不属于流,是Object类的子类。但它融合了InputStream和OutputStream的功能。
支持对随机访问文件的读取和写入。*/
//writeData();
RandomAccessFile in = new RandomAccessFile("e.txt", "rw");
int i = in.readInt();
long filePointer = in.getFilePointer();
System.out.println("指针位置:"+filePointer);
double v = in.readDouble();
filePointer = in.getFilePointer();
System.out.println("指针位置:"+filePointer);
boolean b = in.readBoolean();
filePointer = in.getFilePointer();
System.out.println("指针位置:" + filePointer);
String s = in.readUTF();
filePointer = in.getFilePointer();
System.out.println("指针位置:" + filePointer);
//定位文件指针的位置
in.seek(13);
s = in.readUTF();
System.out.println(i);
System.out.println(v);
System.out.println(b);
System.out.println(s);
System.out.println(s);
}
private static void writeData() throws IOException {
RandomAccessFile out = new RandomAccessFile("e.txt", "rw");
out.writeInt(200);
out.writeDouble(32.2);
out.writeBoolean(false);
out.writeUTF("你好");
}
序列化流和反序列化流的概述和使用
- 序列化流的概述
所谓的序列化:就是把对象通过流的方式存储到文件中.注意:此对象 要重写Serializable 接口才能被序列化
反序列化:就是把文件中存储的对象以流的方式还原成对象
序列化流: ObjectOutputStream
反序列化流: ObjectInputStream
像这样一个接口中如果没有方法,那么这样的接口我们将其称之为标记接口(用来给类打标记的,相当于猪肉身上盖个章) - 一个对象可以被序列化的前提是这个对象对应的类必须实现Serializable接口
public static void main(String[] args) throws IOException, ClassNotFoundException {
//所谓的
//序列化:就是把对象通过流的方式存储到文件中.
//反序列化:就是把文件中存储的对象以流的方式还原成对象
// writeData();
readData();
}
private static void readData() throws IOException, ClassNotFoundException {
ObjectInputStream in = new ObjectInputStream(new FileInputStream("student.txt"));
Student s = (Student) in.readObject();
System.out.println(s.getName()+"=="+s.getAge());
}
private static void writeData() throws IOException {
Student s1 = new Student("张三", 23);
//NotSerializableException
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("student.txt"));
out.writeObject(s1);
out.close();
}
//Serializable
//如果想要一个类的对象,能被序列化,要求该类要实现 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;
}
}
如何解决序列化时候的黄色警告线问题
- 我们的一个类可以被序列化的前提是需要这个类实现Serializable接口,就需要给这个类添加一个标记.
- 在完成序列化以后,序列化文件中还存在一个标记,然后在进行反序列化的时候,
会验证这个标记和序列化前的标记是否一致,如果一致就正常进行反序列化,如果 - 不一致就报错了. 而现在我们把这个类做了修改,将相当于更改了标记,而导致这两个标记不一致,就报错了.
- 解决问题: 只要让这个两个标记一致,就不会报错了吧
- 怎么让这两个标记一致呢? 不用担心,很简单,难道你们没有看见黄色警告线吗? alt+enter, 生成出来
private static final long serialVersionUID = -7602640005373026150L;
Properties的概述和作为Map集合的使用
-
Properties的概述
Properties 类表示了一个持久的属性集。
Properties 可保存在流中或从流中加载。
属性列表中每个键及其对应值都是一个字符串。
Properties父类是Hashtable 属于双列集合,这个集合中的键和值都是字符串 Properties不能指定泛型
public static void main(String[] args) {
//Properties 他的键和值的数据类型,已经默认为String
Properties properties = new Properties();
/* properties.put("username","zhangsan");
Object username = properties.get("username");
*/
properties.setProperty("username", "zhangsan");
String username = properties.getProperty("username2");
// String username = properties.getProperty("username2","aaa");
System.out.println(username);
System.out.println(properties);
}
Properties的特殊功能使用
-
Properties的特殊功能
-
public Object setProperty(String key,String value)
添加元素
-
public String getProperty(String key)
获取元素
注:方法在此属性列表中搜索具有指定键的属性。 如果在此属性列表中找不到该键,则会检查默 认属性列表及其默认值(递归)。 如果未找到该属性,则该方法返回null 。
-
public Set stringPropertyNames()
获取所有的键的集合
-
public static void main(String[] args) throws IOException {
Properties properties = new Properties();
properties.setProperty("username","李四");
properties.setProperty("password","654321");
properties.store(new FileOutputStream("MyUser.properties"),null);
}
Properties的load()和store()功能
Properties的load()和store()功能
Properties和IO流进行配合使用:
- public void load(Reader reader): 读取键值对数据把数据存储到Properties中
- public void store(Writer writer, String comments)把Properties集合中的键值对数据写入到文件中, comments注释
Properties properties = new Properties();
properties.load(new FileInputStream("MyUser.properties"));
properties.store(new FileOutputStream("MyUser.properties"),null);
判断文件中是否有指定的键如果有就修改值的
需求:我有一个文本文件,我知道数据是键值对形式的,但是不知道内容是什么。
请写一个程序判断是否有“lisi”这样的键存在,如果有就改变其值为”100”
分析:
- a: 把文本文件中的数据加载到Properties集合中
- b: 判断这个集合中是否有"lisi"这个键
- 如果有直接修改其值为100
- c: 把集合中的数据再次存储到文本文件中
public static void main(String[] args) throws IOException {
Properties ps = new Properties();
ps.setProperty("lisi","aaa");
ps.setProperty("a","aaa");
ps.setProperty("b","aaa");
ps.setProperty("c","aaa");
ps.setProperty("d","aaa");
ps.store(new FileOutputStream("d.txt"),null);
Properties p = new Properties();
p.load(new FileInputStream("d.txt"));
Set<String> strings = p.stringPropertyNames();
for (String string : strings) {
if(string.equals("lisi")){
p.setProperty(string,"100");
}
}
p.store(new FileOutputStream("d.txt"),null);
}
SequenceInputStream
- SequenceInputStream
表示其他输入流的逻辑串联。
它从输入流的有序集合开始,
并从第一个输入流开始读取,直到到达文件末尾,接着从第二个输入流读取,
依次类推,直到到达包含的最后一个输入流的文件末尾为止
构造方法
SequenceInputStream(InputStream s1, InputStream s2)
通过记住这两个参数来初始化新创建的 SequenceInputStream(将按顺序读取这两个参数,先读取 s1,然后读取 s2),
以提供从此 SequenceInputStream 读取的字节。
b:构造方法
SequenceInputStream(Enumeration<? extends InputStream> e)
通过记住参数来初始化新创建的 SequenceInputStream,该参数必须是生成运行时类型为 InputStream 对象的 Enumeration 型参数。
案例需求:将a.txt和b.txt两个文本文件的内容合并到c.txt
public static void main(String[] args) throws IOException {
/* A:
案例需求:
将a.txt和b.txt两个文本文件的内容合并到c.txt*/
/* SequenceInputStream(InputStream s1, InputStream s2)
通过记住这两个参数来初始化新创建的 SequenceInputStream(将按顺序读取这两个参数,先读取 s1,然后读取 s2),以提供从此 SequenceInputStream 读取的字节。
*/
FileInputStream in1 = new FileInputStream("a.txt");
FileInputStream in2 = new FileInputStream("b.txt");
FileInputStream in3 = new FileInputStream("b.txt");
SequenceInputStream allIn = new SequenceInputStream(in1, in2);
SequenceInputStream allIn2 = new SequenceInputStream(allIn, in3);
FileOutputStream out = new FileOutputStream("ff.txt");
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();
}
采用SequenceInputStream来改进
public static void main(String[] args) throws IOException {
FileInputStream in1 = new FileInputStream("a.txt");
FileInputStream in2 = new FileInputStream("b.txt");
FileInputStream in3 = new FileInputStream("b.txt");
Vector<FileInputStream> vector = new Vector<>();
vector.add(in1);
vector.add(in2);
vector.add(in3);
/* SequenceInputStream(Enumeration < ? extends InputStream > e)
通过记住参数来初始化新创建的 SequenceInputStream,该参数必须是生成运行时类型为 InputStream 对象的 Enumeration 型参数。*/
// Enumeration
Enumeration<FileInputStream> elements = vector.elements();
SequenceInputStream allIn = new SequenceInputStream(elements);
FileOutputStream out = new FileOutputStream("ff.txt");
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();
}