IO流:用于处理设备上数据。
流:可以理解数据的流动,就是一个数据流。IO流最终要以对象来体现,对象都存在IO包中。
流也进行分类:
1:输入流(读)和输出流(写)。
2:因为处理的数据不同,分为字节流和字符流。
字节流:
处理字节数据的流对象。设备上的数据无论是图片或者dvd,文字,它们都以二进制存储的。
二进制的最终都是以一个8位为数据单元进行体现,所以计算机中的最小数据单元就是字节。
意味着,字节流可以处理设备上的所有数据,所以字节流一样可以处理字符数据。
InputStream(字节读取流)
// 创建一个读取流
文件操作流: FileInputStream fis = new FileInputStream("e:\\1.txt");
//定义一个缓冲区数组,存储数据
byte[] bys = new byte[1024];
int len;
while((len=fis.read(bys))!=-1)//常见的写法,往数组里读数据,!=-1 读到最后一位
// ,返回len读了多长
{
System.out.print(new String(bys, 0, len));
//把bytes的前len个,封装成新字符串打印输出
}
OutputStream(字节写入流)
FileOutputStream fos = new FileOutputStream("e:\\1.txt")//写数据
fos.writer("哈哈大笑".getBytes());
字符流:
字符每个国家都不一样,所以涉及到了字符编码问题,那么GBK编码的中文用unicode编码解析是有问题的,
所以需要获取中文字节数据的同时+ 指定的编码表才可以解析正确数据。为了方便于文字的解析,
所以将字节流和编码表封装成对象,这个对象就是字符流。只要操作字符数据,优先考虑使用字符流体系。
Reader
Writer
高效字符流读取
缓冲区是提高效率用的,给谁提高呢?
BufferedWriter:是给字符输出流提高效率用的,那就意味着,缓冲区对象建立时,
必须要先有流对象。明确要提高具体的流对象的效率。
FileWriter fw = new FileWriter("bufdemo.txt");
BufferedWriter bufw = new BufferedWriter(fw);//让缓冲区和指定流相关联。
for(int x=0; x<4; x++){
bufw.write(x+"abc");
bufw.newLine(); //写入一个换行符,这个换行符可以依据平台的不同写入不同的换行符。
bufw.flush();//对缓冲区进行刷新,可以让数据到目的地中。
}
bufw.close();//关闭缓冲区,其实就是在关闭具体的流。
--------
BufferedReader:
FileReader fr = new FileReader("bufdemo.txt");
BufferedReader bufr = new BufferedReader(fr);
String line = null;
while((line=bufr.readLine())!=null){ //readLine方法返回的时候是不带换行符的。
System.out.println(line);
}
bufr.close();
流的操作规律:
1,明确源和目的。
数据源:就是需要读取,可以使用两个体系:InputStream、Reader;
数据汇:就是需要写入,可以使用两个体系:OutputStream、Writer;
2,操作的数据是否是纯文本数据?
如果是:数据源:Reader
数据汇:Writer
如果不是:数据源:InputStream
数据汇:OutputStream
3,虽然确定了一个体系,但是该体系中有太多的对象,到底用哪个呢?
明确操作的数据设备。
数据源对应的设备:硬盘(File),内存(数组),键盘(System.in)
数据汇对应的设备:硬盘(File),内存(数组),控制台(System.out)。
4,需要在基本操作上附加其他功能吗?比如缓冲。
如果需要就进行装饰。
转换流特有功能:转换流可以将字节转成字符,原因在于,将获取到的字节通过查编码表获取到指定对应字符。
转换流的最强功能就是基于 字节流 + 编码表 。没有转换,没有字符流。
发现转换流有一个子类就是操作文件的字符流对象:
InputStreamReader
|--FileReader
OutputStreamWriter
|--FileWrier
想要操作文本文件,必须要进行编码转换,而编码转换动作转换流都完成了。
所以操作文件的流对象只要继承自转换流就可以读取一个字符了。
但是子类有一个局限性,就是子类中使用的编码是固定的,是本机默认的编码表,
对于简体中文版的系统默认码表是GBK。
FileReader fr = new FileReader("a.txt");
InputStreamReader isr = new InputStreamReader(new
FileInputStream("a.txt"),"gbk");
以上两句代码功能一致,
如果仅仅使用平台默认码表,就使用FileReader fr = new FileReader("a.txt"); //因为简化。
如果需要制定码表,必须用转换流。
转换流 = 字节流+编码表。
转换流的子类File = 字节流 + 默认编码表。
凡是操作设备上的文本数据,涉及编码转换,必须使用转换流。
----------------------------------------------------------
编码
由于历史原因,汉字等如何在计算机中以字节存储在着多种标准,最常见的是GB2312(国家标准,表示汉字)
GBK(GB2312的扩展,还能表示繁体字等),UTF-8(国际标准)UFT-16等
用什么编码保存就用什么编码读取,就不会出现乱码!
如何使用其他编码保存?
由OutputStreamWriter构造函数决定(为什么) new OutputStreamWriter(outStream,"UTF-8"),怎么初步判断
用什么编码,记事本"另存为"
读取的编码由InputStreamReader构造函数决定
----------------------------------------------------------
Properties配置文件
通常配置文件里面的数据都是以键值对形式存储的,
使用java.util.Properties类的load()方法 示例:
InputStream in = AccessResource.class.getClassLoader()
.getResourceAsStream("it/cast_0716/p.properties"); //把项目中的文件以流的形式读出来
Properties p = new Properties();
p.load(in); //加载进流
如何访问src目录下的资源文件,
java提供了两种实现方式
第一种方式
访问src目录下,与包同级文件,使用Class对象的getResource方法获得
资源的URL时,传递的参数要以/开头,
这里的斜线就代表项目的bin目录,也就是类加载的跟目录
/如果资源在包下面,要指定包对应的目录
// 需要指定资源的名称
URL resourceURL = AccessResource.class.getResource("/com/rupeng/a.txt");
第二种方式:动态的获取资源的绝对路径,通过类加载器,获取
URL resourceURL = AccessResource.class.getClassLoader()
.getResource("com/rupeng/a.txt");
//直接获取流的方式
InputStream in = AccessResource.class.getClassLoader()
.getResourceAsStream("com/rupeng.a.txt"); //前面不加斜线
注意:
子类不能抛出父类没有声明的检查异常
在当前编码时,我们不能确定当前类的方法在以后子类覆盖时会抛出声明类型的一次,为了保证前期代码的安全
就禁止子类方法抛出父类方法没有声明的异常,
如果父类方法声明抛出了一个检查异常,那么子类方法可以声明抛出此异常的本身或者此异常的子类,子类也可以不抛出任何异常
总结一点,孩子不能比他爹坏
Here is sorted out three small exercise:
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
/*
需求: 将a.jpg的文件字节与b.jpg文件文件字节合并为一个文件c.jpg。
也就是c.jpg中文件的前一部分是a.jpg的内容,后一部分是b.jpg的内容
(不用管生成的c.jpg是否是合法的图片)
* */
public class Test3
{
public static void main(String[] args) throws IOException
{
File f1 = new File("e:\\java.jpg");
File f2 = new File("e:\\林青霞.jpg");
File f3 = new File("e:\\5.png");
merger(f1, f2, f3);
}
//定义一个合并方法,参与运算的有三个参数, 文件1 文件2 合并后的文件3
public static void merger(File aFile,File bFile,File targetFile) throws IOException
{
FileInputStream in = null;
FileInputStream in2 = null;
FileOutputStream out = null;
try
{
//创建文件读写流对象
in = new FileInputStream(aFile);
in2 = new FileInputStream(bFile);
out = new FileOutputStream(targetFile);
//copy a文件的数据,注意 拷贝的文件哪个在前,合并后的显示就先是哪个,因为底层是字节10101存储的
byte[] buff = new byte[1024];
int len=0;
while((len=in.read(buff))!=-1)
{
out.write(buff, 0, len);
}
//copy b 文件的数据
while ((len=in2.read(buff))!=-1)
{
out.write(buff, 0, len);
}
System.out.println("合并成功");
}finally
{
if(in!=null)
{
try
{
in.close();
} catch (IOException e)
{
}
}
if(in2!=null)
{
try
{
in2.close();
} catch (IOException e)
{
}
}
if(out!=null)
{
try
{
out.close();
} catch (IOException e)
{
}
}
}
}
}
import java.io.File;
/*
* 需求:请大家把E:\javase目录下的所有java结尾的文件的绝对路径给输出在控制台
* 扫描文件器
* 分析:
* A:封装目录
* B:获取该目录下所有的文件或者文件夹的File数组
* C:遍历该File数组,得到每一个File对象
* D:判断该File对象是否是文件夹
* 是:递归回到B
* 否:就不搭理它
*
* */
public class FilePathDemo
{
public static void main(String[] args)
{
//封装目录
File srcFolder = new File("e:\\javase");
//递归功能实现
getAlljavaFilePaths(srcFolder);
}
private static void getAlljavaFilePaths(File srcFolder)
{
//获取该目录下所有的文件或者文件夹的File数组
File[] fileArray = srcFolder.listFiles();
//遍历该File数组,得到每一个File对象
for(File file : fileArray)
{
//判断该File对象是否是文件夹
if(file.isDirectory())
{
getAlljavaFilePaths(file);
}else
{
//继续判断是否是以.java结尾
if(file.getName().endsWith(".java"))
{
//就输出该文件的路径
System.out.println(file.getAbsolutePath());
}
}
}
}
}
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.InputStream;
import java.net.URL;
//需求:如何访问项目src下的资源文件
//实际执行时,就是如何访问bin目录下的资源文件
//bin -- java的累加在根路径
//如何获得资源路径
//java提供了两种方式来获得累加在目录下的资源路径
public class AccessResource
{
public static void main(String[] args) throws Exception
{
/*//第一种方式
// 访问src目录下,与包同级文件,使用Class对象的getResource方法获得资源的URL时,传递的参数要以/开头,
// 这里的斜线就代表项目的bin目录,也就是类加载的跟目录
// 如果资源在包下面,要指定包对应的目录
URL resourceURL = AccessResource.class.getResource("/com/rupeng/a.txt");// 需要指定资源的名称
String resourcePath = resourceURL.getFile();// 获得对应的资源路径
System.out.println(resourcePath);
FileReader reader = new FileReader(new File(resourcePath));
BufferedReader bufr = new BufferedReader(reader);
BufferedReader bufr = new BufferedReader(new FileReader(resourcePath)); //装饰模式,二合一
String line = bufr.readLine();
System.out.println(line);*/
//第二种方式:动态的获取资源的绝对路径
URL resourceURL = AccessResource.class.getClassLoader().getResource("com/rupeng/a.txt");
System.out.println(resourceURL);
//直接获取流的方式
InputStream in = AccessResource.class.getClassLoader()
.getResourceAsStream("com/rupeng/a.txt")
}
}