java- I/O(字节流、字符流、缓存流、数据流、对象流)_第一种方式: 使用缓存流把两个数字以字符串的形式写到文件里,再用缓存流以字符串-程序员宅基地

技术标签: 字节流  java  对象流  字符流  缓存流  数据流  

I/O

先看个思维导图呗
在这里插入图片描述

  • 文件对象

1.定义:文件和文件夹都是用File代表。
2.创建一个文件对象
使用绝对路径或者相对路径创建File对象。

package file;
import java.io.File;
public class TestFile {
    
    public static void main(String[] args) {
    
        // 绝对路径
        File f1 = new File("d:/LOLFolder");
        System.out.println("f1的绝对路径:" + f1.getAbsolutePath());
        // 相对路径,相对于工作目录,如果在eclipse中,就是项目目录
        File f2 = new File("LOL.exe");
        System.out.println("f2的绝对路径:" + f2.getAbsolutePath());
  
        // 把f1作为父目录创建文件对象
        File f3 = new File(f1, "LOL.exe");
  
        System.out.println("f3的绝对路径:" + f3.getAbsolutePath());
    }
}

在这里插入图片描述
3.文件常用方法

package file;
 
import java.io.File;
import java.util.Date;
 
public class TestFile {
    
 
    public static void main(String[] args) {
    
 
        File f = new File("d:/LOLFolder/LOL.exe");
        System.out.println("当前文件是:" +f);
        //文件是否存在
        System.out.println("判断是否存在:"+f.exists());
        
        //是否是文件夹
        System.out.println("判断是否是文件夹:"+f.isDirectory());
         
        //是否是文件(非文件夹)
        System.out.println("判断是否是文件:"+f.isFile());
         
        //文件长度
        System.out.println("获取文件的长度:"+f.length());
         
        //文件最后修改时间
        long time = f.lastModified();
        Date d = new Date(time);
        System.out.println("获取文件的最后修改时间:"+d);
        //设置文件修改时间为1970.1.1 08:00:00
        f.setLastModified(0);
         
        //文件重命名
        File f2 =new File("d:/LOLFolder/DOTA.exe");
        f.renameTo(f2);// renameTo方法用于对物理文件名称进行修改,但是并不会修改File对象的name属性。
        System.out.println("把LOL.exe改名成了DOTA.exe");
        
        System.out.println("注意: 需要在D:\\LOLFolder确实存在一个LOL.exe,\r\n才可以看到对应的文件长度、修改时间等信息");
    }
}

在这里插入图片描述

package file;
  
import java.io.File;
import java.io.IOException;
  
public class TestFile {
    
  
    public static void main(String[] args) throws IOException {
    
  
        File f = new File("d:/LOLFolder/skin/garen.ski");
  
        // 以字符串数组的形式,返回当前文件夹下的所有文件(不包含子文件及子文件夹)
        f.list();
  
        // 以文件数组的形式,返回当前文件夹下的所有文件(不包含子文件及子文件夹)
        File[] fs= f.listFiles();
  
        // 以字符串形式返回获取所在文件夹
        f.getParent();
  
        // 以文件形式返回获取所在文件夹
        f.getParentFile();
        // 创建文件夹,如果父文件夹skin不存在,创建就无效
        f.mkdir();
  
        // 创建文件夹,如果父文件夹skin不存在,就会创建父文件夹
        f.mkdirs();
  
        // 创建一个空文件,如果父文件夹skin不存在,就会抛出异常
        f.createNewFile();
        // 所以创建一个空文件之前,通常都会创建父目录
        f.getParentFile().mkdirs();
  
        // 列出所有的盘符c: d: e: 等等
        f.listRoots();
  
        // 刪除文件
        f.delete();
  
        // JVM结束的时候,刪除文件,常用于临时文件的删除
        f.deleteOnExit();
  
    }
}

4.练习

遍历文件夹
在这里插入图片描述

package file;
import java.io.File;

//遍历文件夹 
public class TestFile04 {
    
	public static void main(String[] args) {
    
		File f = new File("c:\\Windows");
  
		// 以文件数组的形式,返回当前文件夹下的所有文件(不包含子文件及子文件夹)
		File[] fs= f.listFiles();
		File max = null;
		File min = null;
		// 取出一个字节大小大于0的文件,用于作为判断最大或最小初始文件
		for(File FS : fs) {
    
			if(f.length() != 0) {
    
				max = FS;
				min = FS;
				break;
			}
		}
		for(int i=0;i<fs.length;i++){
    
			if(fs[i].length()>0&&fs[i].isDirectory()==false){
    
				if(fs[i].length()>max.length()){
    
					max=fs[i];
				}
				if(fs[i].length()<min.length()){
    
					min=fs[i];
				}
			}
		}
		System.out.println("最大的文件是"+max+",其大小是"+max.length()+"字节");
		System.out.println("最小的文件是"+min+",其大小是"+min.length()+"字节");
	}
}

在这里插入图片描述
遍历子文件夹(同上的练习,要求遍历子文件夹)

package file;
import java.io.File;
public class AtWill {
    
	public static void main(String[] args) {
    
		File f = new File("c:\\Windows");
		File[] fs= f.listFiles();
		show(fs);
	}
 
	public static void show(File dir[]) {
    
		if (dir == null) {
    
			return;
		} else {
    
			for (File fi : dir) {
    
				if (fi.isDirectory()) {
    
					show(fi.listFiles());
				}
				if (fi.isFile()) {
    
					System.out.println(fi.getName());
				}
			}
		}
	}
}

注:输出所有文件,问题怎么求最大最小?

package file;

import java.io.File;

public class AtWill {
    
	static File max = null;
	static File min = null;

	public static void main(String[] args) {
    
		File f = new File("D:\\LOLFolder");
		File[] fs= f.listFiles();
		// 取出一个字节大小大于0的文件,用于作为判断最大或最小初始文件
		for(File FS : fs) {
    
			if(f.length() != 0) {
    
				max = FS;
				min = FS;
				break;
			}
		}
		show(fs);
		System.out.println("最大的文件是"+max+",其大小是"+max.length()+"字节");
		System.out.println("最小的文件是"+min+",其大小是"+min.length()+"字节");
	}

	public static void show(File dir[]) {
    
		if (dir == null) {
    
			return;
		} else {
    
			for (File fi : dir) {
    
				if (fi.isDirectory()) {
    
					show(fi.listFiles());
				}
				if (fi.isFile()) {
    
					System.out.println("文件名:"+fi.getName()+" 大小:"+fi.length());
					if(fi.length()>0&&fi.length()<min.length()){
    
						min=fi;
					}	
					if(fi.length()>0&&fi.length()>max.length()){
    
						max=fi;
					}
				}
			}
		}
	}
	
}
  • 什么是流

1.定义:流(Stream)就是一系列的数据。

当不同的介质之间有数据交互的时候,JAVA就使用来实现。
数据源可以是文件,还可以是数据库,网络甚至是其他的程序

比如读取文件的数据到程序中,站在程序的角度来看,就叫做输入流
输入流: InputStream
输出流:OutputStream
在这里插入图片描述
2.文件输入流
如下代码,就建立了一个文件输入流,这个流可以用来把数据从硬盘的文件,读取到JVM(内存)。
目前代码只是建立了流,还没有开始读取。

package stream;
 
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
 
public class TestStream {
    
 
    public static void main(String[] args) {
    
        try {
    
            File f = new File("d:/lol.txt");
            // 创建基于文件的输入流
            FileInputStream fis = new FileInputStream(f);
            // 通过这个输入流,就可以把数据从硬盘,读取到Java的虚拟机中来,也就是读取到内存中
 
        } catch (IOException e) {
    
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
 
    }
}

3.文件输出流

public class TestStream {
    
    public static void main(String[] args) {
    
        try {
    
            File f = new File("d:/LOLFolder/DOTA.exe")
            FileInputStream fis = new FileInputStream(f);
         
            FileOutputStream fos=new FileOutputStream(f);
        } catch (IOException e) {
    
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

注:文件放c盘可能拒绝访问。

  • 字节流

1.定义:用于以字节的形式读取和写入数据。

2.ASCII码

所有的数据存放在计算机中都是以数字的形式存放的。 所以字母就需要转换为数字才能够存放。
比如A就对应的数字65,a对应的数字97。不同的字母和符号对应不同的数字,就是一张码表。
ASCII是这样的一种码表。 只包含简单的英文字母,符号,数字等等。 不包含中文,德文,俄语等复杂的。

字符	十进制数字	十六进制数字
!			33			21
"			34			22
#			35			23
$			36			24
%			37			25
&			38			26
'			39			27
(			40			28
)			41			29
*			42			2A
+			43			2B
,			44			2C
-			45			2D
.			46			2E
/			47			2F
0			48			30
1			49			31
2			50			32
3			51			33
4			52			34
5			53			35
6			54			36
7			55			37
8			56			38
9			57			39
:			58			3A
;			59			3B
<			60			3C
=			61			3D
>			62			3E
@			64			40
A			65			41
B			66			42
C			67			43
D			68			44
E			69			45
F			70			46
G			71			47
H			72			48
I			73			49
J			74			4A
K			75			4B
L			76			4C
M			77			4D
N			78			4E
O			79			4F
P			80			50
Q			81			51
R			82			52
S			83			53
T			84			54
U			85			55
V			86			56
W			87			57
X			88			58
Y			89			59
Z			90			5A
[			91			5B
\			92			5C
]			93			5D
^			94			5E
_			95			5F
`			96			60
a			97			61
b			98			62
c			99			63
d			100			64
e			101			65
f			102			66
g			103			67
h			104			68
i			105			69
j			106			6A
k			107			6B
l			108			6C
m			109			6D
n			110			6E
o			111			6F
p			112			70
q			113			71
r			114			72
s			115			73
t			116			74
u			117			75
v			118			76
w			119			77
x			120			78
y			121			79
z			122			7A
{
    			123			7B
|			124			7C
}			125			7D
~			126			7E

3.以字节流的形式读取文件内容(InputStream)
InputStream是字节输入流,同时也是抽象类,只提供方法声明,不提供方法的具体实现。
FileInputStream 是InputStream子类,以FileInputStream 为例进行文件读取。

package stream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;  
public class TestStream {
    
    public static void main(String[] args) {
    
        try {
    
            //准备文件lol.txt其中的内容是AB,对应的ASCII分别是65 66
            File f =new File("d:/lol.txt");
            //创建基于文件的输入流
            FileInputStream fis =new FileInputStream(f);
            //创建字节数组,其长度就是文件的长度
            byte[] all =new byte[(int) f.length()];
            //以字节流的形式读取文件所有内容
            fis.read(all);
            for (byte b : all) {
    
                //打印出来是65 66
                System.out.println(b);
            }
             
            //每次使用完流,都应该进行关闭
            fis.close();
              
        } catch (IOException e) {
    
            // TODO Auto-generated catch block
            e.printStackTrace();
        }     
    }
}

4.以字节流的形式向文件写入数据(OutputStream)
OutputStream是字节输出流,同时也是抽象类,只提供方法声明,不提供方法的具体实现。
FileOutputStream 是OutputStream子类,以FileOutputStream 为例向文件写出数据
注: 如果文件d:/lol2.txt不存在,写出操作会自动创建该文件。
但是如果是文件 d:/xyz/lol2.txt,而目录xyz又不存在,会抛出异常

package stream;
 
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
 
public class TestStream {
    
    public static void main(String[] args) {
    
        try {
    
            // 准备文件lol2.txt其中的内容是空的
            File f = new File("d:/lol2.txt");
            // 准备长度是2的字节数组,用88,89初始化,其对应的字符分别是X,Y
            byte data[] = {
     88, 89 };
 
            // 创建基于文件的输出流
            FileOutputStream fos = new FileOutputStream(f);
            // 把数据写入到输出流
            fos.write(data);
            // 关闭输出流
            fos.close();
             
        } catch (IOException e) {
    
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
 
    }
}

在这里插入图片描述
5.练习
写入数据到文件
以字节流的形式向文件写入数据 中的例子,当lol2.txt不存在的时候,是会自动创建lol2.txt文件的。
但是,如果是写入数据到d:/lol/lol2.txt,而目录xyz又不存在的话,就会抛出异常。
那么怎么自动创建xyz目录?
如果是多层目录 d:/lol/abc/def/lol2.txt 呢?

package stream;
  
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
  
public class TestStream {
    
  
	public static void main(String[] args) {
            
        try {
    
            File f=new File("d:/lol/abc/bcd/lol2.txt");
            
            // 所以创建一个空文件之前,通常都会创建父目录
            f.getParentFile().mkdirs();
            byte data[] = {
     88, 89 };
           // 创建基于文件的输出流,向文件写入数据
            FileOutputStream fos = new FileOutputStream(f);
             // 把数据写入到输出流
            fos.write(data);
            // 关闭输出流
            fos.close();
             
        } catch (FileNotFoundException e) {
    
            e.printStackTrace();
        } catch (IOException e) {
    
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
         
    }
}

在这里插入图片描述
拆分-合并
在这里插入图片描述

package stream;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;


public class TestStream {
    
	public int count;
	//拆分文件
    public static void onetozero(File file) {
    
        int size = 1024;//1024字符=1k
        if(file.length() == 0) {
    
            System.out.println("文件大小为0,无法拆分。");
            return;
        }
        byte a[] = new byte[(int) file.length()];
        try {
    
        	FileInputStream fis = new FileInputStream(file);
            fis.read(a);
            fis.close();
        } catch (IOException e) {
    
            e.printStackTrace();
        }
        int sum;//拆分文件总数
        if (a.length % size == 0) {
    
            sum = (int) (a.length / size);
        }
        else {
    
            sum = (int) (a.length / size) + 1;//浮点数转变成整数只保留整数部分
        }
        for (int i = 0; i < sum; i++) {
    
            String name = file.getName() + "_" + i;
            //file.getParent()为父目录
            File zerofile = new File(file.getParent(), name);
            byte b[];
            if (i != sum - 1) {
    
                b = Arrays.copyOfRange(a, size * i, size * (i + 1));
            }
            else {
    
                b = Arrays.copyOfRange(a, size * (sum - 1), a.length);
            }
            try {
    
            	FileOutputStream fos = new FileOutputStream(zerofile);
                fos.write(b);
                System.out.println("拆分的文件:" + name + "文件长度为:" + zerofile.length());
                fos.close();
            } catch (IOException e) {
    
                e.printStackTrace();
            }
        }
    }
    //合并文件
    public static void zerotoone(File file) {
    
    	int size = 1024;//1024字符=1k
        if(file.length() == 0) {
    
            System.out.println("文件大小为0,无法拆分。");
            return;
        }
        byte aa[] = new byte[(int) file.length()];
        try {
    
        	FileInputStream fis = new FileInputStream(file);
            fis.read(aa);
            fis.close();
        } catch (IOException e) {
    
            e.printStackTrace();
        }
        int sum;//拆分文件总数
        if (aa.length % size == 0) {
    
            sum = (int) (aa.length / size);
        }
        else {
    
            sum = (int) (aa.length / size) + 1;//浮点数转变成整数只保留整数部分
        }
        //以上获取文件总数sum--------------------------------
        for (int i = 0; i < sum; i++) {
    
            String name = file.getName() + "_" + i;
            File zerofile = new File("d:/LOLFolder/", name);
            File onefile = new File("d:/LOLFolder/", "test_new");
            byte a[] = new byte[(int) zerofile.length()];
            try {
    
            	FileInputStream fis = new FileInputStream(zerofile);
                fis.read(a);
                fis.close();
            }catch (IOException e) {
    
                e.printStackTrace();
            }
            try {
    
             //有true不会覆盖已写入的文本,内部使用append
            	FileOutputStream fos = new FileOutputStream(onefile,true);
                fos.write(a);
                fos.close();
            }catch (IOException e) {
    
                e.printStackTrace();
            }
            zerofile.delete();//合并后删除该文件
            System.out.println(name + "合并入文件:test_new,合并后文件长度为:" + onefile.length());
        }
    }
 
    public static void main(String args[]) {
    
    	/* File file = new File("./test");*/
    	File file = new File("d:/LOLFolder/test.txt");
        System.out.println("获取文件长度为:" + file.length());
        //onetozero(file);
        zerotoone(file);
    } 
}

在这里插入图片描述
在这里插入图片描述

  • 关闭流的方式

1.关闭流
所有的流,无论是输入流还是输出流,使用完毕之后,都应该关闭。 如果不关闭,会产生对资源占用的浪费。 当量比较大的时候,会影响到业务的正常开展。
2.在try中关闭
在try的作用域里关闭文件输入流,在前面的示例中都是使用这种方式,这样做有一个弊端;
如果文件不存在,或者读取的时候出现问题而抛出异常,那么就不会执行这一行关闭流的代码,存在巨大的资源占用隐患。 不推荐使用

package stream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class TestStream {
    
    public static void main(String[] args) {
    
        try {
    
            File f = new File("d:/lol.txt");
            FileInputStream fis = new FileInputStream(f);
            byte[] all = new byte[(int) f.length()];
            fis.read(all);
            for (byte b : all) {
    
                System.out.println(b);
            }
            // 在try 里关闭流
            fis.close();
        } catch (IOException e) {
    
            e.printStackTrace();
        }
    }
}

3.在finally中关闭
这是标准的关闭流的方式

  1. 首先把流的引用声明在try的外面,如果声明在try里面,其作用域无法抵达finally.
  2. 在finally关闭之前,要先判断该引用是否为空
  3. 关闭的时候,需要再一次进行try catch处理

这是标准的严谨的关闭流的方式,但是看上去很繁琐,所以写不重要的或者测试代码的时候,都会采用上面的有隐患try的方式,因为不麻烦~

package stream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class TestStream {
    
    public static void main(String[] args) {
    
        File f = new File("d:/lol.txt");
        FileInputStream fis = null;
        try {
    
            fis = new FileInputStream(f);
            byte[] all = new byte[(int) f.length()];
            fis.read(all);
            for (byte b : all) {
    
                System.out.println(b);
            }
 
        } catch (IOException e) {
    
            e.printStackTrace();
        } finally {
    
            // 在finally 里关闭流
            if (null != fis)
                try {
    
 
                    fis.close();
                } catch (IOException e) {
    
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
        }
    }
}

注:
当fis==null时,执行fis.close()会发生空指针异常。
只有fis!=null,才能执行fis.close()操作。
4.使用try()的方式
把流定义在try()里,try,catch或者finally结束的时候,会自动关闭
这种编写代码的方式叫做 try-with-resources, 这是从JDK7开始支持的技术

所有的流,都实现了一个接口叫做 AutoCloseable,任何类实现了这个接口,都可以在try()中进行实例化。 并且在try, catch, finally结束的时候自动关闭,回收相关资源。
在这里插入图片描述
对比:
在这里插入图片描述

  • 字符流

1.定义:专门用于字符的形式读取和写入数据。

2.使用字符流读取文件(Reader)
字符输入流FileReader 是Reader子类,以FileReader 为例进行文件读取。

package stream;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
public class TestStream {
    
    public static void main(String[] args) {
    
        // 准备文件lol.txt其中的内容是AB
        File f = new File("d:/lol.txt");
        // 创建基于文件的Reader
        try (FileReader fr = new FileReader(f)) {
    
            // 创建字符数组,其长度就是文件的长度
           char[] all = new char[(int) f.length()];
            // 以字符流的形式读取文件所有内容
            fr.read(all);
            for (char b : all) {
    
                // 打印出来是A B
                System.out.println(b);
            }
        } catch (IOException e) {
    
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

3.使用字符流把字符串写入到文件(Writer)
字符输出流FileWriter 是Writer的子类,以FileWriter 为例把字符串写入到文件。

package stream; 
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
public class TestStream {
    
    public static void main(String[] args) {
    
        // 准备文件lol2.txt
        File f = new File("d:/lol2.txt");
        // 创建基于文件的Writer
        try (FileWriter fr = new FileWriter(f)) {
    
            // 以字符流的形式把数据写入到文件中
            String data="abcdefg1234567890";
            char[] cs = data.toCharArray();
           fr.write(cs);
  
        } catch (IOException e) {
    
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

4.练习
加密-解密
在这里插入图片描述

package stream;

import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;

public class TestStream {
    
//文件加密
public static void encodeFile(File encodingFile, File encodedFile) {
    
        
        try {
    
            FileReader fr = new FileReader(encodingFile);
            char[] in = new char[(int) encodingFile.length()];
            fr.read(in);
         
            char[] out = new char[(int) encodingFile.length()];
            System.out.println("解密前的内容为:");
            for(int i=0; i<in.length; i++) {
    
                if((in[i] >= '0'&& in[i] < '9') || (in[i] >= 'A'&& in[i] < 'Z') || (in[i] >= 'a'&& in[i] < 'z')) {
    
                    out[i] = (char) (in[i] +1);
                }
                /*else if(in[i] == '!'||in[i] == '@'||in[i] == '#'||in[i] == '$'||in[i] == '%'||in[i] == '^'||in[i] == '&'||in[i] == '*'
                        ||in[i] == '('||in[i] == ')'||in[i] == '_'||in[i] == '+') out[i] = in[i];*/
                else if(in[i] == '9') out[i] = '0';
                else if(in[i] == 'z') out[i] = 'a';
                else if(in[i] == 'Z')  out[i] = 'A';
                else out[i] = in[i];
                System.out.print(in[i]+ "");
            }
         
            FileWriter fw = new FileWriter(encodedFile);
            fw.write(out);
            fw.close();//必须关闭,不关闭则在缓冲区中,不会写入到txt,不然使用flush方法
            System.out.println();
            System.out.println("加密成功,加密后的内容为:");
            for(int i=0; i<in.length; i++) {
    
                System.out.print(out[i]+ "");
            }
        }catch(Exception e){
    
            e.printStackTrace();
        }
    }
     
//文件解密     
public static void decodeFile(File decodingFile, File decodedFile) {
    
         
        try {
    
        FileReader fr = new FileReader(decodingFile);
        char[] in = new char[(int) decodingFile.length()];
        fr.read(in);
         
        char[] out = new char[(int) decodingFile.length()];
        
        System.out.println("解密后的内容为:");
        for(int i=0; i<in.length; i++) {
    
            if((in[i] > '0'&& in[i] <= '9') || (in[i] > 'A'&& in[i] <= 'Z') || (in[i] > 'a'&& in[i] <= 'z')) {
    
                out[i] = (char) (in[i] -1);
            }
            /*else if(in[i] == '!'||in[i] == '@'||in[i] == '#'||in[i] == '$'||in[i] == '%'||in[i] == '^'||in[i] == '&'||in[i] == '*'
                    ||in[i] == '('||in[i] == ')'||in[i] == '_'||in[i] == '+') out[i] = in[i];*/
            else if(in[i] == '0') out[i] = '9';
            else if(in[i] == 'a') out[i] = 'z';
            else if(in[i] == 'A')  out[i] = 'Z';
            else out[i] = in[i];
            //System.out.print(in[i]+ "\t");
             System.out.print(out[i]);
        }
         
        FileWriter fw = new FileWriter(decodedFile);
        fw.write(out);
        fw.close();//必须关闭,不关闭则在缓冲区中,不会写入到txt,不然使用flush方法
        }catch(Exception e){
    
            e.printStackTrace();
        }
        //System.out.println();
        //System.out.println("解密成功");
       
    }
     
    public static void main(String[] args) {
    
        // TODO 自动生成的方法存根
        File f = new File("d:/LOLFolder/lol.txt");
        File fen = new File("d:/LOLFolder/lol3.txt");
        File fde = new File("d:/LOLFolder/lol4.txt");
        encodeFile(f,fen);
        System.out.println();
        decodeFile(fen,fde);
    }

}

在这里插入图片描述

  • 中文问题

1.编码概念
计算机存放数据只能存放数字,所有的字符都会被转换为不同的数字。
就像一个棋盘一样,不同的字,处于不同的位置,而不同的位置,有不同的数字编号。
有的棋盘很小,只能放数字和英文
有的大一点,还能放中文
有的“足够”大,能够放下世界人民所使用的所有文字和符号

如图所示,英文字符 A 能够放在所有的棋盘里,而且位置都差不多
中文字符, 中文字符 能够放在后两种棋盘里,并且位置不一样,而且在小的那个棋盘里,就放不下中文
在这里插入图片描述
2.常见编码
ISO-8859-1 ASCII 数字和西欧字母
GBK GB2312 BIG5 中文
UNICODE (统一码,万国码)

ISO-8859-1 包含 ASCII
GB2312 是简体中文,BIG5是繁体中文,GBK同时包含简体和繁体以及日文。
UNICODE 包括了所有的文字,无论中文,英文,藏文,法文,世界所有的文字都包含其中

3.UNICODE和UTF
UNICODE:按照UNICODE的方式来存储数据,就会有很大的浪费。
比如在ISO-8859-1中,a 字符对应的数字是0x61
UNICODE中对应的数字是 0x00000061,倘若一篇文章大部分都是英文字母,那么按照UNICODE的方式进行数据保存就会消耗很多空间

在这种情况下,就出现了UNICODE的各种减肥子编码, 比如UTF-8对数字和字母就使用一个字节,而对汉字就使用3个字节,从而达到了减肥还能保证健康的效果
UTF-8,UTF-16和UTF-32 针对不同类型的数据有不同的减肥效果,一般说来UTF-8是比较常用的方式

4.Java采用的是Unicode
写在.java源代码中的汉字,在执行之后,都会变成JVM中的字符。
而这些中文字符采用的编码方式,都是使用UNICODE. "中"字对应的UNICODE是4E2D,所以在内存中,实际保存的数据就是十六进制的0x4E2D, 也就是十进制的20013。

package stream;
public class TestStream {
    
    public static void main(String[] args) {
    
        String str = "中";
    }
}

5.一个汉字使用不同编码方式的表现

以字符 中 为例,查看其在不同编码方式下的值是多少,也即在不同的棋盘上的位置。

package stream;
 
import java.io.UnsupportedEncodingException;
 
public class TestStream {
    
 
    public static void main(String[] args) {
    
        String str = "中";
        showCode(str);
    }
 
    private static void showCode(String str) {
    
        String[] encodes = {
     "BIG5", "GBK", "GB2312", "UTF-8", "UTF-16", "UTF-32" };
        for (String encode : encodes) {
    
            showCode(str, encode);
        }
 
    }
 
    private static void showCode(String str, String encode) {
    
        try {
    
            System.out.printf("字符: \"%s\" 的在编码方式%s下的十六进制值是%n", str, encode);
            byte[] bs = str.getBytes(encode);
 
            for (byte b : bs) {
    
                int i = b&0xff;
                System.out.print(Integer.toHexString(i) + "\t");
            }
            System.out.println();
            System.out.println();
        } catch (UnsupportedEncodingException e) {
    
            System.out.printf("UnsupportedEncodingException: %s编码方式无法解析字符%s\n", encode, str);
        }
    }
}

在这里插入图片描述
6.文件的编码方式-记事本
接下来讲,字符在文件中的保存
字符保存在文件中肯定也是以数字形式保存的,即对应在不同的棋盘上的不同的数字
用记事本打开任意文本文件,并且另存为,就能够在编码这里看到一个下拉。
ANSI 这个不是ASCII的意思,而是采用本地编码的意思。如果你是中文的操作系统,就会使GBK,如果是英文的就会是ISO-8859-1
Unicode UNICODE原生的编码方式
Unicode big endian另一个 UNICODE编码方式
UTF-8 最常见的UTF-8编码方式,数字和字母用一个字节, 汉字用3个字节。
在这里插入图片描述
7.文件的编码方式-eclipse
eclipse也有类似的编码方式,右键任意文本文件,点击最下面的"property"
就可以看到Text file encoding
也有ISO-8859-1,GBK,UTF-8等等选项。
其他的US-ASCII,UTF-16,UTF-16BE,UTF-16LE不常用。
在这里插入图片描述
8.用FileInputStream 字节流正确读取中文
为了能够正确的读取中文内容

  1. 必须了解文本是以哪种编码方式保存字符的
  2. 使用字节流读取了文本后,再使用对应的编码方式去识别这些数字,得到正确的字符
    如本例,一个文件中的内容是字符,编码方式是GBK,那么读出来的数据一定是D6D0。
    再使用GBK编码方式识别D6D0,就能正确的得到字符

注: 在GBK的棋盘上找到的中字后,JVM会自动找到中在UNICODE这个棋盘上对应的数字,并且以UNICODE上的数字保存在内存中。

package stream;   
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException; 
public class TestStream {
    
    public static void main(String[] args) {
    
        File f = new File("E:\\project\\j2se\\src\\test.txt");
        try (FileInputStream fis = new FileInputStream(f);) {
    
            byte[] all = new byte[(int) f.length()];
            fis.read(all);
   
            //文件中读出来的数据是
            System.out.println("文件中读出来的数据是:");
            for (byte b : all)
            {
    
                int i = b&0x000000ff;  //只取16进制的后两位
              System.out.println(Integer.toHexString(i));
            }
            System.out.println("把这个数字,放在GBK的棋盘上去:");
            String str = new String(all,"GBK");
            System.out.println(str);
        } catch (IOException e) {
    
            // TODO Auto-generated catch block
            e.printStackTrace();
        } 
    }
}

在这里插入图片描述
9.用FileReader 字符流正确读取中文
FileReader得到的是字符,所以一定是已经把字节根据某种编码识别成了字符了
而FileReader使用的编码方式是Charset.defaultCharset()的返回值,如果是中文的操作系统,就是GBK
FileReader是不能手动设置编码方式的,为了使用其他的编码方式,只能使用InputStreamReader来代替,像这样:

new InputStreamReader(new FileInputStream(f),Charset.forName(“UTF-8”));

在本例中,用记事本另存为UTF-8格式,然后用UTF-8就能识别对应的中文了。

解释: 为什么中字前面有一个?
如果是使用记事本另存为UTF-8的格式,那么在第一个字节有一个标示符,叫做BOM用来标志这个文件是用UTF-8来编码的。

package stream;
 
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
 
public class TestStream {
    
 
    public static void main(String[] args) throws UnsupportedEncodingException, FileNotFoundException {
    
        File f = new File("D:\\lol2.txt");
        System.out.println("默认编码方式:"+Charset.defaultCharset());
        //FileReader得到的是字符,所以一定是已经把字节根据某种编码识别成了字符了
        //而FileReader使用的编码方式是Charset.defaultCharset()的返回值,如果是中文的操作系统,就是GBK
        try (FileReader fr = new FileReader(f)) {
    
            char[] cs = new char[(int) f.length()];
            fr.read(cs);
            System.out.printf("FileReader会使用默认的编码方式%s,识别出来的字符是:%n",Charset.defaultCharset());
            System.out.println(new String(cs));
        } catch (IOException e) {
    
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        //FileReader是不能手动设置编码方式的,为了使用其他的编码方式,只能使用InputStreamReader来代替
        //并且使用new InputStreamReader(new FileInputStream(f),Charset.forName("UTF-8")); 这样的形式
        try (InputStreamReader isr = new InputStreamReader(new FileInputStream(f),Charset.forName("UTF-8"))) {
    
            char[] cs = new char[(int) f.length()];
            isr.read(cs);
            System.out.printf("InputStreamReader 指定编码方式UTF-8,识别出来的字符是:%n");
            System.out.println(new String(cs));
        } catch (IOException e) {
    
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
         
    }
}

在这里插入图片描述
在这里插入图片描述
10.练习
数字对应的中文:找出 E5 B1 8C 这3个十六进制对应UTF-8编码的汉字。
转化为字节存入数组,找一个文件(创建项目文本)写入,然后读取文件(UTF-8格式)

package stream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.nio.CharBuffer;
 
/*
 *   找出 E5 B1 8C 这3个十六进制对应UTF-8编码的汉字
 * 1.把这三个字节按字节流写入到编码格式为UTF-8的文件中去
 * 2.从文件中按照字符流UTF-8读出这个字符
 * 3.把这个字符用String套上,打印出来
 *  注意:写入文件是字节,读出来是字符,同时注意读出来时的编码设置
 */
public class EncodingDemo1 {
    
 
    public static void main(String[] args) {
    
        // TODO Auto-generated method stub
        byte[] bytes = {
     (byte) 0xE5, (byte) 0xB1, (byte) 0x8C };
 
        try {
    
            parseChineseFromHex(bytes);
        } catch (IOException e) {
    
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
 
    private static void parseChineseFromHex(byte[] bytes) throws IOException {
    
        // TODO Auto-generated method stub
        File file = new File("EncodingDemo1.txt");
        if (!file.exists()) {
    
            // 如果存在父目录,把上层的目录结构全部补全
            if (null != file.getParentFile())
                file.getParentFile().mkdirs();
            // 创建实体文件
            file.createNewFile();
 
        }
        // 文件在项目的最外层路径下,而不是包目录下
        //System.out.println(file.getAbsolutePath());
        // 写入文件中
        try (FileOutputStream output = new FileOutputStream(file)) {
    
            output.write(bytes);
        }
 
        // 读出来
        try (InputStreamReader reader = new InputStreamReader(new FileInputStream(file), "UTF-8")) {
    
            // 只有一个字符
            char[] cbuf = new char[1];
            reader.read(cbuf);
            System.out.println(new String(cbuf));
        }
    }
 
}   

在这里插入图片描述
在这里插入图片描述
移除BOM

如果用记事本根据UTF-8编码保存汉字就会在最前面生成一段标示符,这个标示符用于表示该文件是使用UTF-8编码的。
找出这段标示符对应的十六进制,并且开发一个方法,自动去除这段标示符

package io;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.CharBuffer;
import java.util.Arrays;
 
/*
 * 问题: UTF-8格式保存的文件最前面存在一段标示符BOM,标示它是UTF-8编码的文件
 *      找出这段标示符的十六机制,并开发一个方法把这段自动移出
 *  思路:1.EncodingDemo1.java中的EncodingDemo1.txt的编码修改为UTF-8
 *      2.从EncodingDemo.txt中按照UTF-8格式读出所有字符
 *      3.将字符用十六机制表示出来,观察、结果与“ E5 B1 8C ”的不同之处
 *      4.把观察的结果记录到byte[]数组中
 *      5.把包含BOM的内容byte[]数组去掉上面的观察结果的数组得到移除后的结果
 *      6.把移除后的byte[]数组通过int转换成十六进制和打印成String
 * 注意:字节转换为int才方便打印成十六进制的格式
 * 疑问:若上一个程序结束后直接读取该文件,并不能读到BOM,而必须的手动再修改下该文件的编码格式
 *      实际我也只是点击了另存,并没选择它新的编码格式,它默认帮我选择了UTF-8,默认的不是UTF-8?
 *结果:经百度发现的确windows简体中文操作系统的ANSI编码指向的是GBK编码
 */
public class EncodingDemo2 {
    
    public static void main(String[] args) {
    
        // TODO Auto-generated method stub
        File file = new File("EncodingDemo2.txt");
        try {
    
            parseBOMFromUTF8File(file);
        } catch (FileNotFoundException e) {
    
            // TODO Auto-generated catch block
            if (null != file.getParentFile())
                file.getParentFile().mkdirs();
            try {
    
                file.createNewFile();
            } catch (IOException e1) {
    
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }
        }
    }
 
    private static void parseBOMFromUTF8File(File file) throws FileNotFoundException {
    
        // TODO Auto-generated method stub
        try (FileInputStream input = new FileInputStream(file)) {
    
            byte[] content = new byte[(int) file.length()];
            input.read(content);
            System.out.println(new String(content, "UTF-8"));
            System.out.println("编码修改为UTF-8读取到的十六进制为:");
            for (byte b : content) {
    
                // 留意int是4个字节,而byte是1个字节
                System.out.print(Integer.toHexString(b & 0x000000ff));
            }
            System.out.println();
            byte[] bom = new byte[3];
            bom[0] = (byte) 0xef;
            bom[1] = (byte) 0xbb;
            bom[2] = (byte) 0xbf;
            byte[] withoutBOM = removeBOM(content,bom);
            System.out.print("去除BOM后的结果为:");
            for (byte b : withoutBOM) {
    
                // 注意字节转换为int才方便打印成十六进制的格式
                int i = b & 0xff;
                System.out.print(Integer.toHexString(i));
            }
            System.out.println();
            System.out.println("去除BOM后的结果为:" + new String(withoutBOM, "UTF-8"));
            // String的"e5b18c"怎么解读成byte[] bytes = { (byte) 0xE5, (byte) 0xB1, (byte) 0x8C };
//              答案的方式更合适,还是针对byte[]字符进行操作比较方便
             
        } catch (IOException e) {
    
            // TODO: handle exception
            e.printStackTrace();
        }
    }
 
    // 移除BOM标示符
    private static byte[] removeBOM(byte[] content,byte[] bom) {
    
        // TODO Auto-generated method stub
        return Arrays.copyOfRange(content, bom.length, content.length);
    }
 
}

在这里插入图片描述
在这里插入图片描述

  • 缓存流

1.为什么使用缓存流?
以介质是硬盘为例,字节流和字符流的弊端:
在每一次读写的时候,都会访问硬盘。 如果读写的频率比较高的时候,其性能表现不佳。

为了解决以上弊端,采用缓存流。
缓存流在读取的时候,会一次性读较多的数据到缓存中,以后每一次的读取,都是在缓存中访问,直到缓存中的数据读取完毕,再到硬盘中读取。

缓存流在写入数据的时候,会先把数据写入到缓存区,直到缓存区达到一定的量,才把这些数据,一起写入到硬盘中去。按照这种操作模式,就不会像字节流,字符流那样每写一个字节都访问硬盘,从而减少了IO操作。

2.使用缓存流读取数据
缓存字符输入流 BufferedReader 可以一次读取一行数据。

package stream;
  
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
  
public class TestStream {
    
  
    public static void main(String[] args) {
    
        // 准备文件lol.txt其中的内容是
        // garen kill teemo
        // teemo revive after 1 minutes
        // teemo try to garen, but killed again
        File f = new File("d:/lol.txt");
        // 创建文件字符流
        // 缓存流必须建立在一个存在的流的基础上
        try (
                FileReader fr = new FileReader(f);
                BufferedReader br = new BufferedReader(fr);
            )
        {
    
            while (true) {
    
                // 一次读一行
                String line = br.readLine();
                if (null == line)
                    break;
                System.out.println(line);
            }
        } catch (IOException e) {
    
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
  
    }
}

3.使用缓存流写出数据
BufferedReader 缓存字符输出流, 可以一次写出一行数据

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class TestStream {
    
		public static void main(String[] args) {
    
			try {
    
				BufferedReader br=new BufferedReader(new FileReader("data/17软件1班"));
				BufferedWriter bw=new BufferedWriter(new FileWriter("data/17软件1班副本本"));
				String str="";
				while((str=br.readLine())!=null){
    
					System.out.println(str);
					bw.write(str+"\n");
				}
				br.close();
				bw.flush();
				bw.close();
			} catch (FileNotFoundException e) {
    
				e.printStackTrace();
			} catch (IOException e) {
    
				e.printStackTrace();
			}
		}
}

PrintWriter 缓存字符输出流, 可以一次写出一行数据。

package stream;
   
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
   
public class TestStream {
    
   
    public static void main(String[] args) {
    
        // 向文件lol2.txt中写入三行语句
        File f = new File("d:/lol2.txt");
          
        try (
                // 创建文件字符流
                FileWriter fw = new FileWriter(f);
                // 缓存流必须建立在一个存在的流的基础上              
                PrintWriter pw = new PrintWriter(fw);              
        ) {
    
            pw.println("garen kill teemo");
            pw.println("teemo revive after 1 minutes");
            pw.println("teemo try to garen, but killed again");
        } catch (IOException e) {
    
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
   
    }
}

PrintWriter和BufferedReader区别:

  1. PrintWriter的print、println方法可以接受任意类型的参数,而BufferedWriter的write方法只能接受字符、字符数组和字符串;

  2. PrintWriter的println方法自动添加换行,BufferedWriter需要显示调用newLine方法;

  3. PrintWriter的方法不会抛异常,若关心异常,需要调用checkError方法看是否有异常发生;

  4. PrintWriter构造方法可指定参数,实现自动刷新缓存(autoflush);

  5. PrintWriter的构造方法更广。

PrintWriter和BufferedWriter都是继承java.io.Writer,所以很多功能都一样。不过PrintWriter提供println()方法可以写不同平台的换行符,而BufferedWriter可以任意设定缓冲大小。
OutputStream可以直接传给PrintWriter(BufferedWriter不能接收),如:
PrintWriter out = new PrintWriter(new BufferedOutputStream(new FileOutputStream(“foo.out”)));
或者用OutputStreamWriter来将OutputStream转化为Wrtier.这时就可以用BufferedWriter了。

4.flush
有的时候,需要立即把数据写入到硬盘,而不是等缓存满了才写出去。 这时候就需要用到flush。(写入缓冲区,强制写入硬盘)

package stream;   
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
public class TestStream {
    
    public static void main(String[] args) {
    
        //向文件lol2.txt中写入三行语句
        File f =new File("d:/lol2.txt");
        //创建文件字符流
        //缓存流必须建立在一个存在的流的基础上
        try(FileWriter fr = new FileWriter(f);PrintWriter pw = new PrintWriter(fr);) {
    
            pw.println("garen kill teemo");
            //强制把缓存中的数据写入硬盘,无论缓存是否已满
            pw.flush();           
            pw.println("teemo revive after 1 minutes");
            pw.flush();
            pw.println("teemo try to garen, but killed again");
            pw.flush();
        } catch (IOException e) {
    
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

5.练习-移除注释

设计一个方法,用于移除Java文件中的注释
public void removeComments(File javaFile)
比如,移出以//开头的注释行
File f = new File(“d:/LOLFolder/LOL.exe”);
System.out.println(“当前文件是:” +f);
//文件是否存在
System.out.println(“判断是否存在:”+f.exists());
//是否是文件夹
System.out.println(“判断是否是文件夹:”+f.isDirectory());
注: 如果注释在后面,或者是/**/风格的注释,暂不用处理

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
public class Main {
    
    public void removeComments(File javaFile) {
    
        File newfile=new File(javaFile.getParentFile(),"new"+javaFile.getName());
        System.out.println("选中的文件是:"+javaFile.getName());
        try(FileReader fReader=new FileReader(javaFile);
            BufferedReader bufferedReader=new BufferedReader(fReader);
            FileWriter fileWriter=new FileWriter(newfile);
       		PrintWriter printWriter=new PrintWriter(fileWriter);){
    
            while(true) {
    
                String s=bufferedReader.readLine();
                if(s==null) {
    
                    break;
                }
                else {
    
               		 //判断该行是否以//开头,不是的话写入
                    if(!s.trim().startsWith("//")) {
    
                        printWriter.println(s);
                    }
                }
            }
        }
        catch (IOException e) {
    
            // TODO: handle exception
            e.printStackTrace();
        }
    }
    public static void main(String[] args) {
    
        // TODO 自动生成的方法存根
        File javaFile=new File("D:\\Elipse\\练习-拆分文件\\src\\Main.java");
        Main main=new Main();
        main.removeComments(javaFile);
    }
}
  • 数据流

1.分类
DataInputStream 数据输入流
DataOutputStream 数据输出流

2.直接进行字符串的读写
使用数据流的writeUTF()和readUTF() 可以进行数据的格式化顺序读写
如本例,通过DataOutputStream 向文件顺序写出 布尔值,整数和字符串。 然后再通过DataInputStream 顺序读入这些数据。

注: 要用DataInputStream 读取一个文件,这个文件必须是由DataOutputStream 写出的,否则会出现EOFException,因为DataOutputStream 在写出的时候会做一些特殊标记,只有DataInputStream 才能成功的读取。

package stream;
      
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
      
public class TestStream {
    
      
    public static void main(String[] args) {
    
        write();
        read();
    }
 
    private static void read() {
    
        File f =new File("d:/lol.txt");
        try (
                FileInputStream fis  = new FileInputStream(f);
                DataInputStream dis =new DataInputStream(fis);
        ){
    
            boolean b= dis.readBoolean();
            int i = dis.readInt();
            String str = dis.readUTF();
             
            System.out.println("读取到布尔值:"+b);
            System.out.println("读取到整数:"+i);
            System.out.println("读取到字符串:"+str);
 
        } catch (IOException e) {
    
            e.printStackTrace();
        }
         
    }
 
    private static void write() {
    
        File f =new File("d:/lol.txt");
        try (
                FileOutputStream fos  = new FileOutputStream(f);
                DataOutputStream dos =new DataOutputStream(fos);
        ){
    
            dos.writeBoolean(true);
            dos.writeInt(300);
            dos.writeUTF("123 this is gareen");
        } catch (IOException e) {
    
            e.printStackTrace();
        }
         
    }
}

在这里插入图片描述
3.练习-向文件中写入两个数字,然后把这两个数字分别读取出来。
要求
第一种方式: 使用缓存流把两个数字以字符串的形式写到文件里,再用缓存流以字符串的形式读取出来,然后转换为两个数字。
注: 两个数字之间要有分隔符用于区分这两个数字。 比如数字是31和15,如果不使用分隔符,那么就是3115,读取出来就无法识别到底是哪两个数字。 使用分隔符31@15能解决这个问题。

第二种方式: 使用数据流DataOutputStream向文件连续写入两个数字,然后用DataInpuStream连续读取两个数字。

//缓存流
private static void firstMethod() {
    
        final String filePath = "E://123.txt";
        File file = new File(filePath);
            try {
    
                FileWriter fw = new FileWriter(file);
                BufferedWriter bw = new BufferedWriter(fw);
                String str = "31@15";
                bw.write(str);
                bw.close();
                fw.close();
                FileReader fr = new FileReader(file);
                BufferedReader br = new BufferedReader(fr);
                String str1 = br.readLine();
                br.close();
                fr.close();
                System.out.println("拆解前:"+str1);
                String[] str2 = str1.split("@");
                System.out.println("拆解后:");
                for(String i : str2) {
    
                    System.out.println(i);
                }
            } catch (IOException e) {
    
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
 
    }
//数据流
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
 
public class TestData {
    
    public static void main(String[] args) {
    
        write();
        read();
    }
 
    private static void read() {
    
        File f = new File("d:/test.txt");
        try (FileInputStream fis = new FileInputStream(f); DataInputStream dis = new DataInputStream(fis);) {
    
 
            int i = dis.readInt();
            int a = dis.readInt();
 
            System.out.println("读取到整数:" + i);
            System.out.println("读取到整数:" + a);
 
        } catch (IOException e) {
    
            e.printStackTrace();
        }
 
    }
 
    private static void write() {
    
        File f = new File("d:/test.txt");
        try (FileOutputStream fos = new FileOutputStream(f); DataOutputStream dos = new DataOutputStream(fos);) {
    
 
            dos.writeInt(300);
            dos.writeInt(200);
 
        } catch (IOException e) {
    
            e.printStackTrace();
        }
 
    }
}
  • 对象流

1.定义
对象流指的是可以直接把一个对象以流的形式传输给其他的介质,比如硬盘
一个对象以流的形式进行传输,叫做序列化。 该对象所对应的类,必须是实现Serializable接口。

2.序列化一个对象
创建一个Hero对象,设置其名称为garen。
把该对象序列化到一个文件garen.lol。
然后再通过序列化把该文件转换为一个Hero对象
注:把一个对象序列化有一个前提是:这个对象的类,必须实现了Serializable接口

package charactor; 
import java.io.Serializable;
public class Hero implements Serializable {
    //表示这个类当前的版本,如果有了变化,比如新设计了属性,就应该修改这个版本号
    private static final long serialVersionUID = 1L;
    public String name;
    public float hp;
}
package stream;
    
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
  
import charactor.Hero;
    
public class TestStream {
    
    
    public static void main(String[] args) {
    
        //创建一个Hero garen
        //要把Hero对象直接保存在文件上,务必让Hero类实现Serializable接口
        Hero h = new Hero();
        h.name = "garen";
        h.hp = 616;
          
        //准备一个文件用于保存该对象
        File f =new File("d:/garen.lol");
 
        try(
            //创建对象输出流
            FileOutputStream fos = new FileOutputStream(f);
            ObjectOutputStream oos =new ObjectOutputStream(fos);
            //创建对象输入流              
            FileInputStream fis = new FileInputStream(f);
            ObjectInputStream ois =new ObjectInputStream(fis);
        ) {
    
            oos.writeObject(h);
            Hero h2 = (Hero) ois.readObject();
            System.out.println(h2.name);
            System.out.println(h2.hp);
               
        } catch (IOException e) {
    
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
    
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
            
    }
}

在这里插入图片描述
3.分类
ObjectInputStream
ObjectOutputStream

import java.io.Serializable;

public class Student implements Serializable{
    
 private static final long serialVersionUID=1L;
	private String id;
	private String name;
	private int score;
	public Student(String id, String name, int score) {
    
		super();
		this.id = id;
		this.name = name;
		this.score = score;
	}
	public String getId() {
    
		return id;
	}
	public void setId(String id) {
    
		this.id = id;
	}
	public String getName() {
    
		return name;
	}
	public void setName(String name) {
    
		this.name = name;
	}
	public int getScore() {
    
		return score;
	}
	public void setScore(int score) {
    
		this.score = score;
	}
	public String toString() {
    
		return  id +" "+ name +" "+ score;
	}
}
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.ObjectOutputStream;

public class ObjectOutputTest {
    
		public static void main(String[] args) {
    
			try {
    
				BufferedReader br=new BufferedReader(new FileReader("data/17软件1班"));
				ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("data/17软件1班对象"));
				String str="";
				while((str=br.readLine())!=null){
    
     String[] strs=str.split("\t");
					Student stu=new Student(strs[0],strs[1],Integer.parseInt(strs[2]));
					//中间过程可以对学号,姓名和分数进行修改
					System.out.println(str);
					oos.writeObject(stu);					
				}
				br.close();
				oos.flush();
				oos.close();
			} catch (FileNotFoundException e) {
    
				e.printStackTrace();
			} catch (IOException e) {
    
				e.printStackTrace();
			}
		}

}
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class ObjectInputTest {
    
	public static void main(String[] args) {
    
		try {
    
			ObjectInputStream ois=new ObjectInputStream(new FileInputStream("data/17软件1班对象"));
			ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("data/17软件1班对象2"));
			Student student;
			/*(Student)ois.readObject()可以理解为一行一个对象,
			然后将对象强制转化为Student类型存储在数组对象student中*/
			while((student=(Student)ois.readObject())!=null){
    
				student.setScore(student.getScore()+50);
				System.out.println(student);
    oos.writeObject(student);
			}
			ois.close();
			oos.flush();
			oos.close();
		} catch (FileNotFoundException e) {
    
			e.printStackTrace();
		} catch (IOException e) {
    
			//e.printStackTrace();
		} catch (ClassNotFoundException e) {
    
			e.printStackTrace();
		}
	}

}

4.练习-序列化数组

准备一个长度是10,类型是Hero的数组,使用10个Hero对象初始化该数组

然后把该数组序列化到一个文件heros.lol

接着使用ObjectInputStream 读取该文件,并转换为Hero数组,验证该数组中的内容,是否和序列化之前一样

package charactor; 
import java.io.Serializable; 
public class Hero implements Serializable {
    
    //表示这个类当前的版本,如果有了变化,比如新设计了属性,就应该修改这个版本号
    private static final long serialVersionUID = 1L;
    public String name;
    public float hp;
 
}
import java.io.*;
 
public class ObjectStream {
    
    public static void main(String[] args) {
    
        Hero[] h = new Hero[10];
 
        for (int i = 0; i < h.length; i++) {
    
            h[i] = new Hero();
            h[i].hp = 100 + i;
            h[i].name = "hero" + i;
        }
 
        File f = new File("D:/w/w/garen.lol");
 
        try (FileOutputStream fos = new FileOutputStream(f);
                ObjectOutputStream oos = new ObjectOutputStream(fos);
                FileInputStream fis = new FileInputStream(f);
            ObjectInputStream ois = new ObjectInputStream(fis)) {
    
            	oos.writeObject(h);
            	Hero[] h2 = (Hero[]) ois.readObject();
            for (Hero i : h2) {
    
                System.out.println(i.name + ":" + i.hp);
            }
        } catch (IOException e) {
    
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
    
            e.printStackTrace();
        }
    }
}

在这里插入图片描述

  • System.in

自动创建有一个属性的类文件。
通过控制台,获取类名,属性名称,属性类型,根据一个模板文件,自动创建这个类文件,并且为属性提供setter和getter。

public class @class@ {
    
    public @type@ @property@;
    public @class@() {
    
    }
    public void set@Uproperty@(@type@  @property@){
    
        this.@property@ = @property@;
    }
      
    public @type@  get@Uproperty@(){
    
        return this.@property@;
    }
}
import java.io.*;
import java.lang.reflect.Field;
import java.util.Scanner;
 
import javax.management.modelmbean.ModelMBean;
import javax.swing.text.ChangedCharSetException;
 
/**
 * 步骤 4 : 练习-自动创建类
 * @author 14323
 *
 */
public class SystemIn {
    
 
    public static void main(String[] args) throws IOException {
    
        // TODO Auto-generated method stub
        String str = "public class @class@ {\r\n" + 
                "    public @type@ @property@;\r\n" + 
                "    public @class@() {\r\n" + 
                "    }\r\n" + 
                "    public void set@Uproperty@(@type@ @property@){\r\n" + 
                "        this.@property@ = @property@;\r\n" + 
                "    }\r\n" + 
                "      \r\n" + 
                "    public @type@  get@Uproperty@(){\r\n" + 
                "        return this.@property@;\r\n" + 
                "    }\r\n" + 
                "}";
        //创建一个模板文件,并创建文件输出流
        File file = new File("E://C.class");
        FileWriter fw = new FileWriter(file);
        BufferedWriter bw = new BufferedWriter(fw);
        //将模板写入该文件
        bw.write(str);
        bw.close();
        fw.close();
        //调用ScannerByDemo(),获得要替换的数据,并且将各个值依次赋给对应的String
        String[] str1 = ScannerByDemo();
        String ClassName = str1[0];
        String type = str1[1];
        String typeName = str1[2];
        //更改@Uproperty@所对应的数据首字母为大写
        String UtypeName = typeName.substring(0, 1).toUpperCase()+typeName.substring(1);
        //创建文件输入流
        FileReader fr = new FileReader(file);
        BufferedReader br = new BufferedReader(fr);
        
        //实例化一个char类型的数组,用于接收br.read()所读到的数据
        char[] ch = new char[(int) file.length()];
        br.read(ch);
        //将ch转化为string类型后开始替换字符串中相应数据
        String str2 = new String(ch);
		/*	String strs="";
       		String str2="";
		while((strs=br.readLine())!=null){
			str2+=strs+"\n";
		}*/

        String str3 = str2.replaceAll("@class@", ClassName)
                    .replaceAll("@type@", type)
                    .replaceAll("@property@", typeName)
                    .replaceAll("@Uproperty@", UtypeName);
        //新建同名文件把数据写入(覆盖旧文件)
        FileWriter NewFw = new FileWriter(file);
        BufferedWriter NewBw = new BufferedWriter(NewFw);
        NewBw.write(str3);
        NewBw.close();
        NewBw.close();
        System.out.println("类文件创建完成!");
        System.out.println(str3);
         
    }
     
    /**
     * 获得要替换的数据,返回值为String数组
     * @return
     */
    private static String[] ScannerByDemo() {
    
        Scanner input = new Scanner(System.in);
        System.out.println("请输入类名:");
        String ClassName = input.nextLine();
        System.out.println("请输入属性的类型:");
        String type = input.nextLine();
        System.out.println("请输入属性的名称:");
        String typeName = input.nextLine();
        return new String[]{
    ClassName,type,typeName};
    }
}

在这里插入图片描述

  • 综合练习

1.复制文件
复制文件是常见的IO操作,设计如下方法,实现复制源文件srcFile到目标文件destFile

public static void copyFile(String srcFile, String destFile){
}

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
public class copyFile {
    
     
    public static void main(String[] args) {
    
     
        copyFile("before.txt","after.txt");
     
         
    }
 
    public static void copyFile(String scrFile, String destFile) {
    
         
        try(FileReader read = new FileReader(scrFile);BufferedReader bread = new BufferedReader(read);
                FileWriter write = new FileWriter(destFile);PrintWriter pwrite = new PrintWriter(write,true)){
    
             
            while(true) {
    
                 
                String string = bread.readLine();
                if(string == null)
                    break;
                                                 
                pwrite.write(string + "\r\n");
                 
            }
             
        }catch(IOException e) {
    
             
            e.printStackTrace();
        }
    }
}

2.复制文件夹
复制文件夹,实现如下方法,把源文件夹下所有的文件 复制到目标文件夹下(包括子文件夹)

public static void copyFolder(String srcFolder, String destFolder){

}

package stream;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class TestFile {
    
	public static void main(String[] args) throws IOException {
    
        copyFolder("D:\\LOLFolder\\lol\\abc\\bcd","D:\\LOLFolder\\lol");
    }
     
    //复制文件以及文件夹的方法
    public static void copyFolder(String srcFolder,String destFolder) throws IOException {
    
        //创建文件对象
        File oldfile=new File(srcFolder);
         
        //如果该文件夹为空
        if(oldfile.listFiles()==null) {
    
            //在目标文件夹下创建一个名字相同的文件对象
            File newfile=new File(destFolder,oldfile.getName());
             
            //在创建文件之前,要先创建父文件夹
            newfile.getParentFile().mkdirs();
             
            //然后创建同名文件夹
            newfile.mkdir();
             
            //然后返回
            return ;
        }
        //如果文件夹不为空,则遍历该文件夹下的所有文件
        else {
    
            File[] filesInOld=oldfile.listFiles();
            for (File file : filesInOld) {
    
                //System.out.println(file.getAbsolutePath());
                //判断是否是文件
                if(file.isFile()) {
    
                    //如果是文件,则在目标文件夹下创建一个同名的文件对象
                    File newf=new File(destFolder,file.getName());
                    //在创建文件之前,要先创建父文件夹
                    newf.getParentFile().mkdirs();
                    //然后新建这个文件
                    newf.createNewFile();
                     
                    //然后将文件中的内容进行复制
                    //注意,这里要传绝对路径
                    copyFile(file.getAbsolutePath(),newf.getAbsolutePath());
                }
                //判断是否是文件夹
                else if(file.isDirectory()) {
    
                    //如果是文件夹,则进行递归
                    copyFolder(file.getName(),destFolder);
                }
                 
            }
        }
    }
  //复制文件内容的方法
    public static void copyFile(String oldFile,String newFile) throws IOException {
    
        //由于文件夹中可能有字节码文件,比如图像或者视频等等,所以在这里我们使用字节流进行复制,
        //如果文件中只有文本文件,那我们就可以使用高效的字符缓冲流进行复制
         
        //创建文件对象
        File oldfile=new File(oldFile);
        File newfile=new File(newFile);
         
        //注意,这里的形参必须是D:\\TestLoL的绝对路径,不然的话fis对象会在当前项目目录去寻找要复制的文件
        //创建字节输入流对象
        FileInputStream fis=new FileInputStream(oldfile);
        //创建字节输出流对象
        FileOutputStream fos=new FileOutputStream(newfile);
         
        //读写数据
        byte[] bys=new byte[(int)oldfile.length()];   //定义一个字节数组存储读取到的字节数
        int len;   //保存实际读取到的字节数
        while((len=fis.read(bys))!=-1) {
    
            fos.write(bys, 0, len);
        }
         
        //释放资源
        fis.close();
        fos.close();
    }
}

3.查找文件内容
public static void search(File folder, String search);

假设你的项目目录是 e:/project,遍历这个目录下所有的java文件(包括子文件夹),找出文件内容包括 Magic的那些文件,并打印出来。

package file;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Scanner;

public class SearchContent {
    
	public static void main(String[] args) {
    
		File f = new File("D:\\LOLFolder");
		File[] dir= f.listFiles();
		Scanner scanner=new Scanner(System.in);
		System.out.println("输入你想查找的内容:");
		String search=scanner.nextLine();
		System.out.printf("\n内容包括%s的那些文件:%n",search);
		search(dir,search);
		System.out.println("\n查找结束。");
	}
	public static void search(File dir[], String search){
    
		if (dir == null) {
    
			return;
		} else {
    
			for (File fi : dir) {
    
				if (fi.isDirectory()) {
    
					search(fi.listFiles(), search);
				}
				if (fi.isFile()&&fi.getName().endsWith(".java")) {
    
					try(BufferedReader br = new BufferedReader(new FileReader(fi));){
    
						while(true){
    
		                    String line=br.readLine();
		                    if(line==null){
    
		                        break;
		                    }
		                    if(line.contains(search)){
    
		                        System.out.printf("文件:%s%n",fi.getAbsolutePath());
		                        break;
		                    }
		                }
					} catch (FileNotFoundException e) {
    
						// TODO Auto-generated catch block
						e.printStackTrace();
					}catch (IOException e) {
    
						// TODO Auto-generated catch block
						e.printStackTrace();
					}       
				}
			}
		}		
	}
}

在这里插入图片描述

  • 流关系图

1.流关系图
这个图把本章节学到的流关系做了个简单整理

  1. 流分为字节流和字符流
  2. 字节流下面常用的又有数据流和对象流
  3. 字符流下面常用的又有缓存流
    在这里插入图片描述

2.其他流
除了上图所接触的流之外,还有很多其他流,如图所示InputStream下面有很多的子类。 这些子类不需要立即掌握,他们大体上用法是差不多的,只是在一些特殊场合下用起来更方便,在工作中用到的时候再进行学习就行了。
在这里插入图片描述

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_42878202/article/details/99707955

智能推荐

5个超厉害的资源搜索网站,每一款都可以让你的资源满满!_最全资源搜索引擎-程序员宅基地

文章浏览阅读1.6w次,点赞8次,收藏41次。生活中我们无时不刻不都要在网站搜索资源,但就是缺少一个趁手的资源搜索网站,如果有一个比较好的资源搜索网站可以帮助我们节省一大半时间!今天小编在这里为大家分享5款超厉害的资源搜索网站,每一款都可以让你的资源丰富精彩!网盘传奇一款最有效的网盘资源搜索网站你还在为找网站里面的资源而烦恼找不到什么合适的工具而烦恼吗?这款网站传奇网站汇聚了4853w个资源,并且它每一天都会持续更新资源;..._最全资源搜索引擎

Book类的设计(Java)_6-1 book类的设计java-程序员宅基地

文章浏览阅读4.5k次,点赞5次,收藏18次。阅读测试程序,设计一个Book类。函数接口定义:class Book{}该类有 四个私有属性 分别是 书籍名称、 价格、 作者、 出版年份,以及相应的set 与get方法;该类有一个含有四个参数的构造方法,这四个参数依次是 书籍名称、 价格、 作者、 出版年份 。裁判测试程序样例:import java.util.*;public class Main { public static void main(String[] args) { List <Book>_6-1 book类的设计java

基于微信小程序的校园导航小程序设计与实现_校园导航微信小程序系统的设计与实现-程序员宅基地

文章浏览阅读613次,点赞28次,收藏27次。相比于以前的传统手工管理方式,智能化的管理方式可以大幅降低学校的运营人员成本,实现了校园导航的标准化、制度化、程序化的管理,有效地防止了校园导航的随意管理,提高了信息的处理速度和精确度,能够及时、准确地查询和修正建筑速看等信息。课题主要采用微信小程序、SpringBoot架构技术,前端以小程序页面呈现给学生,结合后台java语言使页面更加完善,后台使用MySQL数据库进行数据存储。微信小程序主要包括学生信息、校园简介、建筑速看、系统信息等功能,从而实现智能化的管理方式,提高工作效率。

有状态和无状态登录

传统上用户登陆状态会以 Session 的形式保存在服务器上,而 Session ID 则保存在前端的 Cookie 中;而使用 JWT 以后,用户的认证信息将会以 Token 的形式保存在前端,服务器不需要保存任何的用户状态,这也就是为什么 JWT 被称为无状态登陆的原因,无状态登陆最大的优势就是完美支持分布式部署,可以使用一个 Token 发送给不同的服务器,而所有的服务器都会返回同样的结果。有状态和无状态最大的区别就是服务端会不会保存客户端的信息。

九大角度全方位对比Android、iOS开发_ios 开发角度-程序员宅基地

文章浏览阅读784次。发表于10小时前| 2674次阅读| 来源TechCrunch| 19 条评论| 作者Jon EvansiOSAndroid应用开发产品编程语言JavaObjective-C摘要:即便Android市场份额已经超过80%,对于开发者来说,使用哪一个平台做开发仍然很难选择。本文从开发环境、配置、UX设计、语言、API、网络、分享、碎片化、发布等九个方面把Android和iOS_ios 开发角度

搜索引擎的发展历史

搜索引擎的发展历史可以追溯到20世纪90年代初,随着互联网的快速发展和信息量的急剧增加,人们开始感受到了获取和管理信息的挑战。这些阶段展示了搜索引擎在技术和商业模式上的不断演进,以满足用户对信息获取的不断增长的需求。

随便推点

控制对象的特性_控制对象特性-程序员宅基地

文章浏览阅读990次。对象特性是指控制对象的输出参数和输入参数之间的相互作用规律。放大系数K描述控制对象特性的静态特性参数。它的意义是:输出量的变化量和输入量的变化量之比。时间常数T当输入量发生变化后,所引起输出量变化的快慢。(动态参数) ..._控制对象特性

FRP搭建内网穿透(亲测有效)_locyanfrp-程序员宅基地

文章浏览阅读5.7w次,点赞50次,收藏276次。FRP搭建内网穿透1.概述:frp可以通过有公网IP的的服务器将内网的主机暴露给互联网,从而实现通过外网能直接访问到内网主机;frp有服务端和客户端,服务端需要装在有公网ip的服务器上,客户端装在内网主机上。2.简单的图解:3.准备工作:1.一个域名(www.test.xyz)2.一台有公网IP的服务器(阿里云、腾讯云等都行)3.一台内网主机4.下载frp,选择适合的版本下载解压如下:我这里服务器端和客户端都放在了/usr/local/frp/目录下4.执行命令# 服务器端给执_locyanfrp

UVA 12534 - Binary Matrix 2 (网络流‘最小费用最大流’ZKW)_uva12534-程序员宅基地

文章浏览阅读687次。题目:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=93745#problem/A题意:给出r*c的01矩阵,可以翻转格子使得0表成1,1变成0,求出最小的步数使得每一行中1的个数相等,每一列中1的个数相等。思路:网络流。容量可以保证每一行和每一列的1的个数相等,费用可以算出最小步数。行向列建边,如果该格子是_uva12534

免费SSL证书_csdn alphassl免费申请-程序员宅基地

文章浏览阅读504次。1、Let's Encrypt 90天,支持泛域名2、Buypass:https://www.buypass.com/ssl/resources/go-ssl-technical-specification6个月,单域名3、AlwaysOnSLL:https://alwaysonssl.com/ 1年,单域名 可参考蜗牛(wn789)4、TrustAsia5、Alpha..._csdn alphassl免费申请

测试算法的性能(以选择排序为例)_算法性能测试-程序员宅基地

文章浏览阅读1.6k次。测试算法的性能 很多时候我们需要对算法的性能进行测试,最简单的方式是看算法在特定的数据集上的执行时间,简单的测试算法性能的函数实现见testSort()。【思想】:用clock_t计算某排序算法所需的时间,(endTime - startTime)/ CLOCKS_PER_SEC来表示执行了多少秒。【关于宏CLOCKS_PER_SEC】:以下摘自百度百科,“CLOCKS_PE_算法性能测试

Lane Detection_lanedetectionlite-程序员宅基地

文章浏览阅读1.2k次。fromhttps://towardsdatascience.com/finding-lane-lines-simple-pipeline-for-lane-detection-d02b62e7572bIdentifying lanes of the road is very common task that human driver performs. This is important ..._lanedetectionlite

推荐文章

热门文章

相关标签