前面讲了那么多,都是对java数据的操作,本章来讲讲对文件的操作——IO流。
流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象。即数据在两设备间的传输称为流,流的本质是数据传输,根据数据传输特性将流抽象为各种类,方便更直观的进行数据操作。
我们的IO总的来说可以分两种,一种是只能处理纯字符文件的,叫做字符流,另一种是能处理所有类型的叫做字节流,在每种下,我们又可以分为读取和输出两种操作。
-
字符流操作:
- Reader 读取
- Writer 输出
-
字节流操作:
- InputStream 读取
- OutputStream 输出
我们来尝试读取字符流文件:
首先我们在电脑f盘根目录(当然,你随便在哪都行)建一个txt文本文件,里面写上内容:
然后写上代码:
- public static void main(String[] args) throws IOException {
- Reader reader=new FileReader("F://Test.txt");//获取文件
- int i=reader.read();
- System.out.println(i);
- System.out.println((char)i);//read()方法读取第一个字符“i”
- i=reader.read();
- System.out.println((char)i);//read()方法读取第一个字符“ ”(空格)
- i=reader.read();
- System.out.println((char)i);//read()方法读取第一个字符“a”
- i=reader.read();
- System.out.println((char)i);//read()方法读取第一个字符“m”
- reader.close(); //不想读了,关闭reader
- }
运行的结果为: 以上是Reader读取文件的方式,要一个个字符的读,效率非常慢,但是由上述代码我们可以看出,我们反复在用reader.read()给i这这个变量赋值,然后i打印出来的是我们流中相对应的Unicode码,因此用char强转之后就能变成相对应的字符(可以参考前面的基本类型与变量的char)。还有一点可以看出,我们的流读过一次就没了(被消耗了),这个流就好比你水管里的水一样,流过来你用了就没了,再流进来的就是新的了。 一个个字节的度读太累,因此我们可以用循环来读取整段话:
- public static void main(String[] args) throws IOException {
- Reader reader=new FileReader("F://Test.txt");//获取文件
- int i=0;
- while((i=reader.read())!=-1){//每次重新赋值,并且判断是否读完(等于-1即读完了)
- System.out.println((char)i);
- if(i==-1)
- break;
- }
- reader.close();
- }
读出来的结果是: 我们再来看看往txt文件内写入内容:
- public static void main(String[] args) throws IOException {
- Writer writer = new FileWriter("F://Test.txt");//获取文件路径
- writer.write("我是 JAVA IO");//写入内容
- writer.close();//关闭Writer
- }
这段代码运行之后控制台并没有什么反应,但是我们重新打开这个文件你会发现内容已经变了:
现在你已经学会最基本的IO的操作了,但是我们的IO操作并不仅仅这么简单,还要考虑很多复杂的问题,比如字符编码问题(不信你可以把第一步中的文字换成中文试试),以及文件是否存在(比如去读取一个并不存在的文件),这些事情我们就用常用的字节流操作来处理: 字节流操作,就是把文件转成字节来进行处理的方法,我们来试试它的读取:
- public static void main(String[] args) {
- try {//捕获异常
- File file=new File("F://Test.txt");//用File获取文件
- if(file.isFile() && file.exists()){ //判断文件是否存在(file.isFile()方法判断是否是文件,file.exists()方法判断文件是否存在)
- InputStream inputStream = new FileInputStream(file);
- byte b[]=new byte[(int)file.length()];//创建合适文件大小的数组(file.length()方法可获取文件内容长度)
- inputStream.read(b);//读取文件中的内容到b[]数组
- inputStream.close();//关闭InputStream
- System.out.println(new String(b));
- }else{
- System.out.println("找不到指定的文件");
- }
- } catch (Exception e) {//抛出异常
- System.out.println("读取文件内容出错");
- e.printStackTrace();
- }
- }
字节流操作往txt文件内写入内容:
- public static void main(String[] args) {
- try{
- File file = new File("F://Test.txt");//获取文件
- if(!file.isFile() && !file.exists()){//判断问是否存在(file.isFile()方法判断是否是文件,file.exists()方法判断文件是否存在),若不存在,则创建一个
- file.createNewFile();//创建文件
- }
- OutputStream outputStream=new FileOutputStream(file);
- OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream, "UTF-8");//设置编码为UTF-8
- outputStreamWriter.write("这是输出流");
- outputStreamWriter.close();// 关闭输出流
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
上述代码和之前的代码效果基本差不多,但是他们不仅可以读取txt文件,还可以读取比如照片,视频等别的格式的文件,(有兴趣的话可以试一试把c盘的照片存到d盘去~),输出的代码,大家可以将文件名改成不存在的,你会发现真的就在f盘下创建了这个文件并输出了内容。 IO的应用就这么简单,唯一要注意的两点是:
- 一定要抛异常或者捕获异常
- 用完之后必须关闭流(close()方法)
下面来说说什么叫抛异常或者捕获异常: 在上面的代码中,要么是在main方法后面加上了throws IOException,要么是用了try…catch包着代码。这两者都是处理异常的方法:
- throws是将异常丢给调用它的程序去处理
- try…catch是自己处理
那么什么是异常呢?
-
异常(Exception)就是一些已知可能出现的但是避免不了的非逻辑的错误 比如前面讲除法运算时,出现的除数为0的情况,这种情况可以通过编译器通过,但是我们运行的时候下面却报错了,这个错就是jvm抛给我们的,报错了就影响了程序的正常运行,那么,为了不影响程序正常运行,我们需要手动处理一下:
- public static void main(String[] args) {
- int a = 1;
- int b = 0;
- try {
- System.out.println(a/b);
- } catch (Exception e) {
- System.out.println("除数不能为0");
- }
- }
- public static void main(String[] args) {
- try {
- division(1, 0);//传入1、0两个参数,1、0为方法中a,b的实参
- } catch (Exception e) {
- System.out.println("除数不能为0");
- }
- }
- public static int division(int a, int b) throws Exception{//传入参数a、b,a、b为形参,返回值int类型,并且抛出异常
- return a/b;
- }