IO:input、output,输入输出流
package restudy;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
public class demo02 {
public static void main(String[] args) throws IOException {
// TODO 自动生成的方法存根
//1、创建FileOutputStream对象
// File file = new File("a.txt");
// FileOutputStream fos = new FileOutputStream(file);
//两种创建方式都可以
FileOutputStream fos=new FileOutputStream("a.txt");
//2调用write方法
fos.write(97);
//3、用完要关闭
fos.close();
}
}
package restudy;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
public class demo02 {
public static void main(String[] args) throws IOException {
//写进字节数组
FileOutputStream fos1=new FileOutputStream("a.txt");
byte [] a= {97,98,99,100};
fos1.write(a);
fos1.close();
//指定长度
FileOutputStream fos2 = new FileOutputStream("b.txt");
byte [] b= "北京欢迎你".getBytes();
fos2.write(b,2,4);//2-4,左闭右开
fos2.close();
}
}
java.io.InputStream 抽象类是表示字节输入流的所有类的超类,可以读取字节信息到内存中。它定义了字节输入 流的基本共性功能方法。
常用方法
public void close()
:关闭此输入流并释放与此流相关联的任何系统资源。public int read()
: 从输入流读取数据的下一个字节。返回0-255的int类型,如果没有东西可读,返回-1public int read(byte[] b)
: 从输入流中读取一些字节数,并将它们存储到字节数组 b中 。返回读取到的有效字节个数,没有东西读取时返回-1构造方法
FileInputStream(File file)
: 通过打开与实际文件的连接来创建一个 FileInputStream ,该文件由文件系 统中的 File对象 file命名。FileInputStream(String name)
: 通过打开与实际文件的连接来创建一个 FileInputStream ,该文件由文件 系统中的路径名 name命名。package restudy;
import java.io.FileInputStream;
import java.io.IOException;
public class demo02 {
public static void main(String[] args) throws IOException {
// 创建文件输入流对象
FileInputStream fileInputStream = new FileInputStream("E:\\uu\\a.txt");
int asii;
// 因为读不到数据就返回-1了,所以不等于-1才输出
while ((asii = fileInputStream.read()) != -1) {
System.out.println(asii);
}
fileInputStream.close();
}
}
97
98
99
100
package restudy;
import java.io.FileInputStream;
import java.io.IOException;
public class demo02 {
public static void main(String[] args) throws IOException {
// 创建文件输入流对象
FileInputStream fileInputStream = new FileInputStream("E:\\uu\\c.txt");
int len;
byte[] arr = new byte[2];
while ((len = fileInputStream.read(arr)) != -1) {
// 为什么要这样?因为直接输出的话,第一次AB,第二次CD,第三次ED,就不符合条件的
System.out.println(new String(arr, 0, len));
}
fileInputStream.close();
}
}
AB
CD
E
package restudy;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class demo02 {
public static void main(String[] args) throws IOException {
long start=System.currentTimeMillis();
FileInputStream fis = new FileInputStream("E:\\uu\\p5.png");// 输入
FileOutputStream fos = new FileOutputStream("E:\\uu\\copy_p5.png");// 输出
byte[] b = new byte[1024];// 每次读取1024字节,增快速度
int len;// 长度
// copy
while ((len = fis.read(b)) != -1) {
fos.write(b, 0, len);
}
// close
fos.close();
fis.close();
long end=System.currentTimeMillis();
System.out.println("一共用了"+(end-start)+"毫秒");
}
}
一共用了14毫秒
中文的GBK占2个字节,UTF-8占3个字节,但字节流只能单个字节操作,这样利用字节流来输入输出,都会把2/3个字节拆分开来,不能合在一起变中文
这是一个抽象类,不能直接用,所以只能用他的子类
java.io.Reader 抽象类是表示用于读取字符流的所有类的超类,可以读取字符信息到内存中。它定义了字符输入 流的基本共性功能方法。
public void close()
:关闭此流并释放与此流相关联的任何系统资源。public int read()
: 从输入流读取一个字符。public int read(char[] cbuf)
: 从输入流中读取一些字符,并将它们存储到字符数组 cbuf中 。该类是Reader类的子类
构造方法
FileReader(File file)
: 创建一个新的 FileReader ,给定要读取的File对象。FileReader(String fileName)
: 创建一个新的 FileReader ,给定要读取的文件的名称。package restudy;
import java.io.FileReader;
import java.io.IOException;
public class demo02 {
public static void main(String[] args) throws IOException {
FileReader fileReader = new FileReader("E:\\uu\\a.txt");
char[] c = new char[1024];// 一次读1024字节
int len;// 有效长度
while ((len = fileReader.read(c)) != -1) {
System.out.println(new String(c, 0, len));
}
}
}
你好haha123
java.io.Writer 抽象类是表示用于写出字符流的所有类的超类,将指定的字符信息写出到目的地。它定义了字节 输出流的基本共性功能方法。
void write(int c)
写入单个字符。void write(char[] cbuf)
写入字符数组。abstract void write(char[] cbuf, int off, int len)
写入字符数组的某一部分,off数组的开始索引,len 写的字符个数。void write(String str)
写入字符串。void write(String str, int off, int len)
写入字符串的某一部分,off字符串的开始索引,len写的字符个 数。void flush()
刷新该流的缓冲。void close()
关闭此流,但要先刷新它。构造方法
FileWriter(File file)
: 创建一个新的 FileWriter,给定要读取的File对象。FileWriter(String fileName)
: 创建一个新的 FileWriter,给定要读取的文件的名称字符输出流使用步骤
package restudy;
import java.io.FileWriter;
import java.io.IOException;
public class demo02 {
public static void main(String[] args) throws IOException {
FileWriter fileWriter = new FileWriter("E:\\uu\\d.txt");
fileWriter.write(97);// 写入单个字符
fileWriter.write("\r\n");// 换行
char[] c = { 'a', 'b' };
fileWriter.write(c);// 写入char数组
fileWriter.write("\r\n");
char[] d = { '程', '序', '猿' };
fileWriter.write(d, 0, 2);// 写入char数组中的几个元素
fileWriter.write("\r\n");
fileWriter.write("你好" + "\r\n");// 写入string
String s = "北京欢迎你";
fileWriter.write(s, 0, 3);// 写入string中的几个
fileWriter.write("\r\n");
fileWriter.flush();
fileWriter.close();
}
}
续写和字节流的续写一样,只是对象名字不同而已
在上面的练习中,我们都是把异常直接抛出,这样在实际开发中会被人打爆狗头,所以为了防止被打,还是用 try...catch...finally
来使用比较好
package restudy;
import java.io.FileWriter;
import java.io.IOException;
public class demo02 {
public static void main(String[] args) {
FileWriter fileWriter = null;
// try
try {
fileWriter = new FileWriter("E:\\uu\\d.txt");
fileWriter.write(97);
} catch (IOException e) {// catch
e.printStackTrace();// 写异常
} finally {// 最终不管是不是有,都会执行的代码
try {//但是flush和close本身又有异常,又要抛出异常
if (fileWriter != null) {
fileWriter.flush();
fileWriter.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
可以看到,这个用 try...catch...finally
,非常麻烦,写一大堆看到头皮发麻,但是不这样写又怕被打爆狗头,所以在JDK7之后就有了方便的方法
格式:
try (创建流对象语句,相当于作用域,如果多个,使用';'隔开)
{
// 读写数据
} catch (IOException e) {
e.printStackTrace();
}
package restudy;
import java.io.FileWriter;
import java.io.IOException;
public class demo02 {
public static void main(String[] args) {
//try(xxx),括号里面写创建流对象语句,就是一个作用域
try (FileWriter fileWriter = new FileWriter("E:\\uu\\d.txt")) {
fileWriter.write(98);
} catch (IOException e) {
e.printStackTrace();
}
}
}
这样一下子就简便很多了
Properties 继承 Hashtable,有键与值,都是String类型
构造方法 :public Properties()
:创建一个空的属性列表。
public Object setProperty(String key, String value)
: 保存一对属性。public String getProperty(String key)
:使用此属性列表中指定的键搜索属性值。public Set stringPropertyNames()
:把所有键保存到一个set类型中void store(OutputStream out, String comments)
:把InputStream对象写入到磁盘中,不能写入中文,String comments为注释,但注释不能输入中文(unicode)void store(Writer writer, String comments)
:把Writer对象写入到磁盘中,可以写入中文void load(InputStream inStream)
:从字节输入流(InputStream)中读取属性列表(键和元素对)。void load(Reader reader)
:从字符输入流(Reader)中读取属性列表(键和元素对)。store
方法,保存到硬盘中package restudy;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;
public class demo02 {
public static void main(String[] args) throws IOException {
// 创建Properties对象并赋值
Properties properties = new Properties();
properties.setProperty("华为", "5999");
properties.setProperty("小米", "2999");
FileWriter fileWriter = new FileWriter("E:\\uu\\e.txt");
properties.store(fileWriter, "save data");
fileWriter.close();
}
}
load()
读取文件package restudy;
import java.io.FileReader;
import java.io.IOException;
import java.util.Properties;
import java.util.Set;
public class demo02 {
public static void main(String[] args) throws IOException {
// 创建Properties对象
Properties properties = new Properties();
// 准备要读取的文件
FileReader fileWriter = new FileReader("E:\\uu\\e.txt");
// 读取文件,然后properties就有了对应的键与值
properties.load(fileWriter);
// 使用stringPropertyNames(),把键值都保存到Set集合中
Set<String> str = properties.stringPropertyNames();
// 循环输出
for (String string : str) {
String value = properties.getProperty(string);
System.out.println(string + "==>" + value);
}
fileWriter.close();
}
}
华为==>5999
小米==>2999
字节流进阶版本,更快更强大。字节缓冲流继承字节流,所以方法函数和字节流一样,只是构造方法不一样
构造方法:
public BufferedInputStream(InputStream in)
:创建一个 新的缓冲输入流。public BufferedOutputStream(OutputStream out)
: 创建一个新的缓冲输出流。然后那些操作也是平常的那样子,什么read(),write()也是
构造方法:
public BufferedReader(Reader in)
:创建一个 新的缓冲输入流。public BufferedWriter(Writer out)
: 创建一个新的缓冲输出流众所周知,系统一开始用的是ASCII码,然后有中国加入,又产生了GBK码,后来大家统一用UTF-8或者16、32来使用,不同的码度不同的字节,读出来是不一样的,所以有个转换流
OutputStreamWriter(OutputStream in)
: 创建一个使用默认字符集的字符流。 ,注意FileOutputStream继承OutputStreamWriter,默认为UTF-8OutputStreamWriter(OutputStream in, String charsetName)
: 创建一个指定字符集的字符流。charsetName为转换的码集package restudy;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
public class Deomo03 {
public static void main(String[] args) throws IOException {
// 1.创建OutputStreamWriter对象,
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("E:\\uu\\f.txt"), "UTF-8");
// 2.写入
osw.write("你好");
osw.flush();
osw.close();
}
}
InputStreamReader(InputStream in)
: 创建一个使用默认字符集的字符流。InputStreamReader(InputStream in, String charsetName)
: 创建一个指定字符集的字符流。package restudy;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
public class Deomo03 {
public static void main(String[] args) throws IOException {
InputStreamReader isr1 = new InputStreamReader(new FileInputStream("E:\\uu\\f.txt"), "GBK");// GBK读取
InputStreamReader isr2 = new InputStreamReader(new FileInputStream("E:\\uu\\f.txt"), "UTF-8");// UTF-8读取
int read;
while ((read = isr1.read()) != -1) {
System.out.print((char) read);
}
System.out.println();
while ((read = isr2.read()) != -1) {
System.out.print((char) read);
}
isr1.close();
isr2.close();
}
}
浣犲ソ
你好
UTF-8文件,用GBK来读取,会错误
Java 提供了一种对象序列化的机制。用一个字节序列可以表示一个对象,该字节序列包含该 对象的数据
、对象的类型
和 对象中存储的属性
等信息。字节序列写出到文件之后,相当于文件中持久保存了一个对象的信息。 反之,该字节序列还可以从文件中读取回来,重构对象,对它进行反序列化。 对象的数据 、对象的类型 和 对象中 存储的数据
信息,都可以用来在内存中创建对象。看图理解序列化:
步骤
implements Serializable
构造方法:
public ObjectOutputStream(OutputStream out)
: 创建一个指定OutputStream的ObjectOutputStream。package restudy;
import java.io.Serializable;
public class Person implements Serializable {
int age;
String name;
public Person(int age, String name) {
this.age = age;
this.name = name;
}
}
package restudy;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
public class Deomo03 {
public static void main(String[] args) throws IOException {
Person person = new Person(18, "小芳");
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("E:\\uu\\Person.txt"));
oos.writeObject(person);
oos.close();
}
}
构造方法:
public ObjectInputStream(InputStream in)
: 创建一个指定InputStream的ObjectInputStream。package restudy;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
public class Deomo03 {
public static void main(String[] args) throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("E:\\uu\\Person.txt"));
Object o = ois.readObject();
System.out.println(o);
Person person = (Person) o;
System.out.println(person);
System.out.println(person.age + " " + person.name);
ois.close();
}
}
restudy.Person@9f70c54
restudy.Person@9f70c54
18 小芳
当你序列化完了,再改下对应类中的属性时,会发生错误,比如改成
那么反序列的时候会发生错误
Exception in thread “main” java.io.InvalidClassException: restudy.Person; local class incompatible: stream classdesc serialVersionUID = 7834862679727742011, local class serialVersionUID = -8162237166348967350
at java.base/java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:689)
at java.base/java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1903)
at java.base/java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1772)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2060)
at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1594)
at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:430)
at test/restudy.Deomo03.main(Deomo03.java:11)
因为你序列化和反序列化的类不一样啊,都改了,但是这样还是有办法处理的
在序列化之前,在类中加上private static final long serialVersionUID = 1L;
,其中,常量值随便换的,这样,就算序列了,然后改类中的东西,也能反序列出来
package restudy;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.PrintStream;
public class Deomo03 {
public static void main(String[] args) throws IOException, ClassNotFoundException {
System.out.println(97);// 在控制台输出
PrintStream ps = new PrintStream("E:\\uu\\ps.txt");
System.setOut(ps);// 输出流指向文件
System.out.println(98);// 在文件中输出
}
}
97