文件字节流
在Windows下
绝对路径:C://User/test.txt 相对路径:test.txt
文件字节输入流:
InputStream只是⼀个抽象类,要使用还需要具体的实现类。关于InputStream的实现类有很多,基 本可以认为不同的输⼊设备都可以对应⼀个InputStream类,我们现在只关心从文件中读取,所以使用FileInputStream
当使用完成一个流之后,必须关闭这个流来完成对资源的释放,否则资源会一直被占用:
public static void main(String[] args) {
FileInputStream inputStream = null;
try{
inputStream=new FileInputStream("test.txt");
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
}
finally {
if(inputStream!=null){
try {
inputStream.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
简化写法(语法糖):
public static void main(String[] args) {
try (FileInputStream stream=new FileInputStream("test.txt")){
System.out.println(stream);
}catch (IOException e){
e.printStackTrace();
}
}
英文字母占一个字节,中文占三个字节
public static void main(String[] args) {
try (FileInputStream stream=new FileInputStream("test.txt")){
//剩余多少个字节
System.out.println(stream.available());
//读一个字符
int x =stream.read();
System.out.println((char) x);
//读所有的,前面读取了第一个字母H,此处从后开始读取
int i;
while ((i=stream.read())!=-1){
System.out.print((char) i);
}
//所有内容读取完毕,后面的都不输出了
//分开看方法
byte[] bytes =new byte[3];
while (stream.read(bytes)!=-1)
System.out.println(new String(bytes)); //仅限纯文本变成字符串打印出来
byte[] bytes1=new byte[stream.available()];
stream.read(bytes1);
System.out.println(new String(bytes1));
//跳过n个字节读取
stream.skip(3);
System.out.println((char) stream.read());
}catch (IOException e){
e.printStackTrace();
}
}
文件字节输出流:
//文件字节输出流
try(FileOutputStream stream1=new FileOutputStream("test1.txt",true)) { //true表示开启追加模式
stream1.write('c');
stream1.write("Hello World!".getBytes());
stream1.write("Hello World!".getBytes(),3,3);//从3开始写3个长度:lo ;
stream1.flush();//建议在最后执行一次刷新操作(强制写入)来保证数据正确写入到硬盘文件当中
}catch (IOException e){
e.printStackTrace();
}
拷贝文件:
//拷贝文件
try (FileInputStream in =new FileInputStream("test,txt");FileOutputStream out=new FileOutputStream("test2.txt")){
int s;
while ((s=in.read())!=-1)
out.write(s);
//如果文件很大,加快拷贝速度:
byte[] bytes2=new byte[1024];
int len;
while ((len=in.read(bytes2))!=-1){
out.write(bytes2,0,len);
}
}catch (IOException e){
e.printStackTrace();
}
文件字符流
字符流不同于字节,字符流是以一个具体的字符进行读取,因此它只适合读纯文本的文件,如果是其他类型的文件不适用。
字节流;英文1个字节,中文3个字节。 字符流:中英文都是2个字节
public static void main(String[] args){
try (FileReader reader = new FileReader("test.txt")){
System.out.println((char) reader.read());
}catch (IOException e){
e.printStackTrace();
}
try (FileWriter writer = new FileWriter("test.txt")){
writer.write("eeee");
}catch (IOException e){
e.printStackTrace();
}
//拷贝
try (FileReader reader1 = new FileReader("test.txt");
FileWriter writer1 = new FileWriter("test1.txt")){
char[] chars = new char[3];
int len;
while ((len=reader1.read(chars))!= -1){
writer1.write(chars,0,len);
}
}catch (IOException e){
e.printStackTrace();
}
}
}
文件对象
public static void main(String[] args) throws IOException {
//文件对象
File file = new File("test.txt");
System.out.println(file.exists()); //判断文件是否存在
System.out.println(file.getAbsoluteFile()); //获取绝对路径
file.createNewFile(); //创建文件
file.length(); //获取字节长度
File file1=new File("hello/test2");
System.out.println(file1.mkdirs()); //创建文件夹
}
}
public static void main(String[] args){
File file=new File("Honor(1).mp3");
try (FileInputStream in = new FileInputStream("Honor(1).mp3");
FileOutputStream out =new FileOutputStream("xxx.mp3")){
byte[]bytes=new byte[1024*1024];
int len;
long total =file.length(),sum=0;
while ((len=in.read(bytes))!=-1){
out.write(bytes,0,len);
sum+=len;
System.out.println("文件已拷贝"+(sum*100/total)+"%");
}
}catch (IOException e){
e.printStackTrace();
}
}
/*输出
文件已拷贝10%
文件已拷贝21%
文件已拷贝31%
文件已拷贝42%
文件已拷贝52%
文件已拷贝63%
文件已拷贝73%
文件已拷贝84%
文件已拷贝95%
文件已拷贝100%
*/
缓冲流
当调用mark()之后,输入流会以某种方式保留之后读取的readlimit数量的内容,当读取的数量超过readlimit则之后的内容不会被保留,当调用reset()之后,会使得当前的读取位置回到mark()调用时的位置。
try (BufferedInputStream stream = new BufferedInputStream(new FileInputStream("test.txt"))){
stream.mark(0);
System.out.print((char) stream.read());
System.out.print((char) stream.read());
System.out.println((char) stream.read());
stream.reset();
System.out.print((char) stream.read());
System.out.print((char) stream.read());
System.out.print((char) stream.read());
System.out.print((char) stream.read());
}catch (IOException e){
e.printStackTrace();
}
转换流
读取的是一个字符串或一个个字符,但是只能往一个OutputStream里输出,但是OutputStream只支持byte类型,如果要往里面写入内容,进行数据转换就会很麻烦,可以使用转换流使之简洁:
try (OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream("test.txt"))){
writer.write("aaabbbbccc");
}catch (IOException e){
e.printStackTrace();
}
同样的,现在只拿到一个InputStream,希望能按照字符否方式读取:
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream("test.txt")))){
System.out.println(reader.readLine());
}catch (IOException e){
e.printStackTrace();
}
打印流
public static void main(String[] args){
try (PrintStream stream = new PrintStream(new FileOutputStream("test.txt"))){
stream.println("zzzz");
}catch (IOException e){
e.printStackTrace();
}
}
以及printf的使用(格式化打印)
数据流
数据流DataInputStream也是FilterInputStream的子类,同样采用装饰者模式,最大的不同是它支持基本数据类型的直接读取:
try (DataInputStream stream1= new DataInputStream(new FileInputStream("test.txt"))){
System.out.println(stream1.readBoolean());
}catch (IOException e){
e.printStackTrace();
}
用于写入基本数据:
try (DataOutputStream stream2 = new DataOutputStream(new FileOutputStream("test1.txt"))){
stream2.writeBoolean(false);
}catch (IOException e){
e.printStackTrace();
}
注意:写入的是二进制数据,并不是写入的字符串,使用DataInputStream可以读取,一般它们是配合使用的。
对象流
ObjectOutputStream不仅支持基本数据类型,而且通过对对象的序列化操作,以某种格式来保存对象,来支持对象类型的IO。注意:它不是继承自FilterInputStream。
try (ObjectOutputStream stream3 = new ObjectOutputStream(new FileOutputStream("test.txt"));
ObjectInputStream in = new ObjectInputStream(new FileInputStream("test.txt"))){
List<String>list = new ArrayList<>(Arrays.asList("A","B","C"));
stream3.writeObject(list);
Object o=in.readObject();
System.out.println(o);
}catch (IOException e) {
e.printStackTrace();
}catch (ClassNotFoundException e){
throw new RuntimeException();
}
//输出[A, B, C]
try (ObjectOutputStream out1 = new ObjectOutputStream(new FileOutputStream("test.txt"));
ObjectInputStream in1 = new ObjectInputStream(new FileInputStream("test.txt"))){
Student student = new Student();
student.name="小明";
student.age=19;
out1.writeObject(student);
System.out.println(in1.readObject());
}catch (IOException e){
e.printStackTrace();
}catch (ClassNotFoundException e){
throw new RuntimeException(e);
}
}
static class Student implements Serializable{ //必须实现Serializable接口才能被序列化
private static final long serialVersionUID = 123457;
//在序列化时,会被自动添加这个属性,它代表当前类的版本,我们也可以手动指定版本
public String name;
transient public int age;
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
//输出Student{name='小明', age=0}
如果我们不希望某些数据参与到序列化中进行保存,我们可以添加transient关键字。
在一些JDK内部的源码中也存在大量的transient关键字,使得某些属性不参与序列化,取消这些不必要保存的属性可以节省数据空间占用以及减少序列化时间。