前言
流
流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象。即数据在两设备间的传输称为流,流的本质是数据传输,根据数据传输特性将流抽象为各种类,方便更直观的进行数据操作。
IO流的分类
根据处理数据类型的不同分为:字符流和字节流
根据数据流向不同分为:输入流和输出流
字符流和字节流
字符流的由来: 因为数据编码的不同,而有了对字符进行高效操作的流对象。本质其实就是基于字节流读取时,去查了指定的码表。字节流和字符流的区别:
(1)读写单位不同:字节流以字节(8bit)为单位,字符流以字符为单位,根据码表映射字符,一次可能读多个字节。
(2)处理对象不同:字节流能处理所有类型的数据(如图片、avi等),而字符流只能处理字符类型的数据。
(3)字节流在操作的时候本身是不会用到缓冲区的,是文件本身的直接操作的;而字符流在操作的时候下后是会用到缓冲区的,是通过缓冲区来操作文件,我们将在下面验证这一点。
结论:优先选用字节流。首先因为硬盘上的所有文件都是以字节的形式进行传输或者保存的,包括图片等内容。但是字符只是在内存中才会形成的,所以在开发中,字节流使用广泛。
输入流和输出流
对输入流只能进行读操作,对输出流只能进行写操作,程序中需要根据待传输数据的不同特性而使用不同的流。
(一)读写文件API
<1>FileUtils
File file = new File ("D:/test.txt");
//写文件参数说明
//(file-操作文件,
//"test"-写入内容,
//"utf-8"-编码,
//false-是否跟随原先文本,false则为替换文本)
FileUtils.writeStringToFile (file,"test","utf-8",false);
//读取文件
System.out.println (FileUtils.readFileToString (file,"utf-8"));
<2>原生IO流
public void testFile() throws IOException{
FileInputStream in = null;
FileOutputStream fs = null;
String oldPath = "D:/test.txt";
String newPath = "D:/testNew.txt";
try {
//实例化文件,并判断文件是否存在
File oldfile=new File(oldPath);
if(oldfile.exists()){
//初始化文件输入与输出流
in=new FileInputStream (oldPath);
fs=new FileOutputStream(newPath, false);
//定义存放读取数据的数组
byte[] buffer=new byte[10];
int length;
while(true){
int len=in.read(buffer);//当文件读完,返回-1,否则返回读取文件长度
/*注:输出读取的当前文件内容方法
* String s=new String(buffer);
* s.trim();(去除字符串前后两端的空格)
*/
if(len==-1)break;
fs.write(buffer);
}
System.out.println("OK");
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}finally{
in.close();
fs.close();
}
}
<3>SpringBoot中的读写文件
待补充
(二)工作中遇到的问题
<1>classPath读取文件,写文件会写到编译后的文件,而不在resources目录下
//通过读取json,然后修改json中的key值,写回文件(后面发现,读写不是同一路径)
final ClassPathResource resource = new ClassPathResource("test/test.json");
final File filePath = resource.getFile();
String returnString="";
try{
returnString = FileUtils.readFileToString(filePath, "UTF-8");
JSONArray jsonArray = new JSONArray (returnString);
for(int i=0;i<jsonArray.length ();i++){
if(jsonArray.getJSONObject (i).getString ("key").equals ("test")){
jsonArray.getJSONObject (i).put ("test","newTestVal");
}
}
returnString = jsonArray.toString ();
}catch (IOException e){
e.printStackTrace ();
}catch (JSONException e){
e.printStackTrace ();
}
FileUtils.writeStringToFile (filePath, returnString,"utf-8",false);
解决办法:
若需要写回文件,还是用已知路径进行读写操作,不要用classPath API读取文件。
<2>classPath读取文件,打包成jar包或者war包后,路径会出现异常。
final ClassPathResource resource = new ClassPathResource("test/test.json");
//本地运行没错,在jar包中运行路径不正确,导致
//java.lang.IllegalArgumentException: URI is not hierarchical
final File filePath = resource.getFile();
try{
returnString = FileUtils.readFileToString(filePath, "UTF-8");
}catch (IOException e){
e.printStackTrace ();
}
解决办法:
String returnString = "",line;
try{
Class clazz = this.getClass();
//InputStream路径在开发环境和jar包内都是一致的
InputStream in = clazz.getClassLoader().getResourceAsStream("test/test.json");
InputStreamReader inputStreamReader = new InputStreamReader (in);
BufferedReader bufferedReader = new BufferedReader (inputStreamReader);
while((line = bufferedReader.readLine()) != null) {
returnString += line;
}
}catch (Exception e){
e.printStackTrace ();
}
return returnString ;