Java自学之I/O编程

I/O(Input/Output,输入/输出)可以实现数据的读取与写入操作,Java针对I/O操作的实现提供了java.io工具包,此包的核心组成由File类、InputStream类OutputStream类、Reader类、Writer类、Serializable接口。

File文件操作

java.io.File类是一个与文件本身操作有关的类,此类可以实现文件的创建、删除、重命名、取得文件大侠、修改日期等常见的系统文件操作。

File类文件基本操作方法

方法类型描述
public File(String pathname)构造给定一个要操作文件的完整路径
public File(File parent,String child)构造给定要操作文件的父路径和子文件名称
public boolean createNewFile() throws IOException普通创建文件
public boolean delete()普通删除文件
public boolean exists()普通判断给定路径是否存在
package cn.uihtml.demo;
 import java.io.File;
 public class JavaDemo {
     public static void main(String[] args) throws Exception {
         File file = new File('D:\uihtml.txt');
         if(file.exists()) {
             file.delete();
         } else {
             file.createNewFile();
         }
     }
 }

在使用File类进行文件创建时需要设置完整路径,但是对于不同操作系统,文件的路径分隔符也有所不同。为了解决这个问题,在java.io.File类中提供了一个路径分隔符的常量【public static final String separator】。

package cn.uihtml.demo;
 import java.io.File;
 public class JavaDemo {
     public static void main(String[] args) throws Exception {
         File file = new File('D:' + File.separator + 'uihtml.txt');
         if (file.exists()) {
             file.delete();
         } else {
             file.creatNewFile();
         }
     }
 }

使用File类创建文件时必须保证父路径存在,之前的案例程序时直接在根路径下进行文件创建,所以用户可以直接使用createNewFile()方法创建文件。如果此时文件需要保存在特定的目录中,则必须先创建父目录后才可以进行文件创建。

方法类型描述
public File getParentFile()普通找到一个指定路径的父路径
public boolean mkdirs()普通创建指定目录
package cn.uihtml.demo;
 import java.io.File;
 public class JavaDemo {
     public static void main(String[] args) throws Exception {
         File file = new File('D:' + File.separator + 'hello' + File.sepatator + 'demo' + 'uihtml.txt');
         if (file.getParentFile().exists()) {
             file.getParentFile().mkdirs();
         } 
         if (file.exists()) {
             file.delete();
         } else {
             file.createNewFile();
         }
     }
 }

获取文件信息的方法

方法类型描述
public boolean canRead()普通文件是否能读
public boolean canWrite()普通文件是否能写
public boolean canExecute()普通文件是否能执行
public long length()普通获取文件大小,返回字节长度
public long lastModiffied()普通获得最后一次修改日期
public boolean isDiretory()普通是否是目录
public boolean isFile()普通是否是文件
public boolean isHidden()普通是否隐藏
public File[] listFiles()普通列出目录中全部文件信息

字节流与字符流

在程序中所有的数据都是以流的方式进行传输或保存的,在流操作中存在有输入流和输出流的概念。

当程序需要通过数据文件读取数据时就可以利用输入流来完成,而当程序需要将数据保存到文件时,就可以使用输出流完成。

数据流是一种重要的资源操作,而执行资源操作时一般按照以下几个步骤进行。

  1. 如果要操作的是文件,那么首先要通过File类对象找到一个要操作的文件路径(路径可能存在,也可能不存在,如果不存在,则要创建路径)。
  2. 通过字节流或字符流的子类为字节流或字符流的对象实例化(向上转型)。
  3. 执行读/写操作。
  4. 一定要关闭操作的资源(close()),不管随后代码如果操作,资源永远要关闭。

字节流操作:InputStream、OutputStream

字符流操作:Writer、Reader

OutputStream字节输出流

常用方法

方法类型描述
public abstract void write(int b) throws IOException普通输出单个字节数据
public void write(byte[] b) throws IOException普通输出一组字节数据
public void write(byte[] b,int off,int len) throws IOException普通输出部分字节数据
public void close() throws IOException普通关闭输出流
public void flush() throws IOException普通刷新缓冲区

OutputStream定义了公共的字节输出操作,由于其定义为一个抽象类,所以需要依靠子类进行对象实例化,如果需要通过程序向文件进行内容输出,可以使用FileOutputStream子类。

FileOutputStream类常用方法

方法类型描述
public FileOutputStream(File file) throws FileNotFoundException构造采用覆盖的形式创建文件输出流
public FileOutStream(File file,boolean append) throws FileNotFoundException构造采用覆盖或追加的形式创建文件输出流
package cn.uihtml.demo;
 import java.io,File;
 import java.io.FileOutputStream;
 import java.io.OutputStream;
 public class JavaDemo {
     public static void main(String[] args) throws Exception{
         File file = new File('D:' + File.separator + 'hello' + File.separator + 'uihtml.txt');
         if (!file.getParentFile().exists()) {
             file.getParentFile().mkdirs()
         }
         OutputStream output = new FileOutputStream(file);
         String str = '中华人民共和国万岁,中华人民大团结万岁';
         output.write(str.getBytes());
         output.close();
     }
 }

使用AutoCloseable自动关闭接口

package cn.uihtml.demo;
 import java.io,File;
 import java.io.FileOutputStream;
 import java.io.OutputStream;
 public class JavaDemo {
     public static void main(String[] args) throws Exception{
         File file = new File('D:' + File.separator + 'hello' + File.separator + 'uihtml.txt');
         if (!file.getParentFile().exists()) {
             file.getParentFile().mkdirs()
         }
         try (OutputStream output = new FileOutputStream(file,true)) {
             String str = '中华人民共和国万岁,中华人民大团结万岁';
             output.write(str.getBytes());
         } catch (IOException e) {
             e.printStackTrace();
         }    
     }
 }

InputStream字节输入流

当程序需要通过数据流进行字节数据读取时就可以利用java.io.InputStream类来实现。

InputStream类常用方法

方法类型描述
public abstract int read() throws IOException普通读取单个字节数据,如果现在已经读取到底了,返回-1
public int read(byte[] b) throws IOException普通读取一组字节数据,返回的是读取的个数;如果没有数据,且已经读到底则返回-1
public int read(byte b,int off,int len) throws IOException普通读取一组字节数据(只占数组的部分)
public void close() throws IOException普通关闭输出流
public byte[] readAllBytes() throws IOException普通读取输入流全部字节数据
public long transferTo(OutputStream out) throws IOException普通输入流转存到输出流
package cn.uihtml.demo;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.InputStream;
 public class JavaDemo {
     public static void main(String[] args) throws Exception {
         File file = new File('D:' + File.separator + 'hello' + File.separator + 'uihtml.txt');
         if (file.exists()) {
             InputStream input = new FileInputStream(file);
             byte data[] = new byte[1024];
             int len = input.read(data);
             System.out.println(new String(data,0,len));
             input.close();
         }
     }
 }

Writer字符输出流

在底层通信处理中都是依靠字节实现的数据交互,在程序中为了方便进行中文的数据处理,往往都会采用字符数据类型。

字符流最大的特点是可以直接进行字符串数据输出。

Writer类常用方法

方法类型描述
public Writer append(CharSequence csq) throws IOException普通追加输出内容
public void write(char[] cbuf) throws IOException普通输出字符数组
public void write(int c) throws IOException普通输出单个字符
public void write(String str) throws IOException普通输出字符串
public abstract void flush() throws IOException普通刷新缓冲区
public abstract void close() throws IOException普通关闭输入流

Writer类进行文件操作时可以利用FileWriter子类进行对象实例化。

FileWriter类常用方法

方法类型描述
public FileWriter(File file) throws IOException构造采用覆盖的形式创建文件输出流
public FileWriter(File file,boolean append) throws IOException构造采用覆盖或追加的形式创建文件输出流
package cn.uihtml.demo;
 import java.io.File;
 import java.io.FileWriter;
 import java.io.Writer;
 public class JavaDemo {
     public static void main(String[] args) throws Exception {
         File file = new File('D:' + File.separator + 'hello' + File.separator + 'uihtml.txt');
         if (!file.getParentFile().exists()) {
             file.getParentFile().mkdirs();
         }
         Writer out = new FileWriter(file);
         out.write('蜀国国主-->刘备');
         out.append('蜀国宰相-->诸葛亮');
         out.close();
     }
 }

与OutputStream类相比,Writer可以直接输出字符串内容,同时也可以在输出后继续利用append()方法追加输出内容。

Reader字符输入流

Reader类常用方法

方法类别描述
public int read() throws IOException普通读取单个字符,无数据读取时返回-1
public int read(char[] cbuf) throws IOException普通读取多个字符,并返回读取个数
public long skip(long n) throws IOException普通跳过指定的字符个数后读取
public boolean ready() throws IOException普通是否可以开始读取数据
public abstract void close() throws IOException普通关闭输入流
package cn.uihtml.demo;
 import java.io.File;
 import java.io.FileReader;
 import java.io.Reader;
 public class JavaDemo {
     publi static void main(String[] args) throws Exception {
         File file = new File('D:' + File.separator + 'hello' + File.separator + 'uihtml.txt');
         if (file.exists()) {
             Reader in = new FileReader(file);
             char data[] = new char[1024];
             in.skip(9);
             int len = in.read(data);
             System.out.println(new String(data,0,len));
             in.close();
         }
     }
 }

字节流与字符流的区别

虽然java.io包中提供字节流和字符流两类处理支持类,但是在数据传输(或者将数据保存在磁盘)时所操作的数据依然为字节数据,字符数据都是通过缓冲区进行处理后得到的内容。两类操作流最大的区别就在于字符流使用到了缓冲区(这样更适合进行中文数据的操作),而字节流是直接进行数据处理操作。所以当使用字符输出流进行输出时就必须使用Flushable接口中提供的flush()方法强制性刷新缓冲区中的内容,否则数据将不会输出

package cn.uihtml.demo;
 import java.io.File;
 import java.io.FileWriter;
 import java.io.Writer;
 public class JavaDemo {
     public static void main(String[] args) throws Exception {
         File file = new File('D:' + File.separator + 'hello' + File.separator + 'uihtml.txt');
         if (!file.getParentFile().exists()) {
             file.getParentFile().mkdirs();
         }
         Writer out = new FileWriter(file);
         out.write('蜀国国主-->刘备');
         out.append('蜀国宰相-->诸葛亮');
         out.flush();
         out.close();
     }
 }

转换流

转换流的设计目的是解决字节流与字符流之间操作类型的转换。java.io包中提供有两个转换流。

  • OutputStreamWriter:字节输出流转换为字符输出流
  • InputStreamReader:字节输入流转换为字符输入流
package cn.uihtml.demo;
 import java.io.*;
 public class JavaDemo {
     public static void main(String[] args) throws Exception {
         File file = new File("D:" + File.separator + "hello" + File.separator + "uihtml.txt");
         if (!file.getParentFile().exists()) {
             file.getParentFile().mkdirs();
         }
         OutputStream output = new FileOutputStream(file);
         Writer out = new OutputStreamWriter(output);
         out.write("蜀国国主-->刘备");
         out.append("蜀国宰相-->诸葛亮");
         out.flush();
         out.close();
         output.close();
     }
 }

字符编码

在计算机的世界中,所有显示文字都是按照其指定的数字编码进行保存。

ISO8859-1:是一种国际通用单字节编码,最多只能表示0~255的字符范围,主要在英文传输中使用。

GBK/GB2312:中文的国际编码,专门用来表示文字,是双字节编码。GBK可以表示简体中文和繁体中文,而GB2312只能表示简体中文。

UNICODE:十六进制编码,可以准确地表示出任何语言文字,此编码不兼容ISO8859-1编码。

UTF-8:兼容ISO8859-1编码,可表示所有的语言字符。

内存操作流

内存操作流是以内存作为操作终端实现的I/O数据处理,与文件操作不同的地方在于,内存操作流不会进行磁盘数据操作。Java中提供两种内存操作流。

  • 字节内存操作流:ByteArrayOutputStream、ByteArrayInputStream。
  • 字符内存操作流:CharArrayWriter、CharArrayReader。

利用内存流实现大小写字母转换的操作

package cn.uihtml.demo;
 import java.io.*;
 public class JavaDemo {
     public static void main(String[] args) throws Exception{
         String str = 'www.uihtml.cn';
         Input input = new ByteArrayInputStream(str.getBytes());
         Output output = new ByteArrayOutputStream();
         int data = 0;
         while ((data = input.read()) != -1) {
             output.write(Character.toUpperCase(data));
         }
         System.out.println(output);
         input.close();
         output.close();
     }
 }

管道流

管道流的主要作用是可以进行两个线程间的通信,分为管道输出流【PipedOutputStream、PipedWriter】、管道输入流【PipedInputStream、PipedReader】。如果要想进行管扫输出,则必须把输出流连接在输入流之上。

使用字节管道流实现线程通信

package cn.uihtml.demo;
 import java.io.*;
 class SendThread implements Runnable {
     private PipeOutputStream output;
     public SendThread () {
         this.output = new PipedOutputStream();
     }
     @Override
     public void run() {
         try {
             this.output.write("蜀国国主-->刘备".getBytes());
             this.output.close();
         } catch (IOException e) {
             e.printStackTrace();
         }
     }
     public PipedOutputStream getOutput() {
         return output;
     }
 }
package cn.uihtml.demo;
 import java.io.*;
 class ReceiveThread implements Runnable {
     private PipedInputStream input;
     public ReceiveThread() {
         this.input = new PipedInputStream();
     }
     @Override
     public void run() {
         byte data[] = new byte[1024];
         int len = 0;
         ByteArrayOutputStream bos = new ByteArrayOutputStream();
         try {
             while((len = this.input.read(data)) != -1) {
                 bos.write(data,0,len);
             }
             System.out.println(new String(bos.toByteArray()));
             bos.close();
         } catch(IOException e) {
             e.printStackTrace();
         }
         try {
             this.input.close();
         } catch (IOException e) {
             e.printStackTrace();
         }
     }
     public PipedInputStream getInput() {
         return input;
     }
 }
package cn.uihtml.demo;
 class JavaDemo {
     public static void main(String[] args) throws Exception {
         SendThread send = new SendThread();
         ReceiveThread receive = new ReceiveThread();
         send.getOutput().connect(receive.getInput());
         new Thread(send,"消息发送线程:").start();
         new Thread(receive,"消息接收线程:").start();
     }
 }

BufferedReader缓冲输入流

BufferedReader提供了一种字符流的缓冲区数据读取,利用此类进行数据读取时会将读取到的数据暂时保存在缓冲区,而后利用其内部提供的方法将读取到的内容一次性取出。

常用方法

方法类型描述
public BufferedReader(Read in)构造接收一个Reader类的实例
public String readLine() throws IOException普通一次性从缓冲区中将内容全部读取出来

对象序列化

对象序列化,就是把一个对象变为二进制的数据流的一种方法。通过对象序列化可以方便地实现对象的传输或存储。

一个类的对象想被序列化,则对象所在的类必须实现java.io.Serializable接口。此接口并没有提供任何抽象方法,只是一个标识接口,只表示一种对象可以被序列化的能力。

package cn.uihtml.demo;
 class Member implements Serializable {
     private String name;
     private int age;
     public Member(String name,int age) {
         this.name = name;
         this.age = age;
     }
     public void setName(String name) {
         this.name = name;
     }
     public void setAge(int age) {
         this.age = age;
     }
     public String getName() {
         return this.name;
     }
     public int getAge() {
         return this.age;
     }
     @Override
     public String toString() {
         return "姓名:" + this.name + ",年龄:" + this.age;
     }
 }

本程序定义的Member类实现了Serializable接口,所以此类的实例化对象都允许进行二进制传输。

序列化与反序列化处理

Serializable接口只是定义了某一个类的对象是否允许序列化的支持,然后对于对象序列化的反序列化的具体实现,则需要依靠ObjectOutputStream与ObjectInputStream两类完成。

ObjectOutputStream类可以将对象转为特定格式的二进制数据输出,ObjectInputStream可以读取ObjectOutputStream类输出的二进制对象数据,并将其转为具体类型的对象返回。

ObjectOutputStream类常用方法

方法类型描述
public ObjectOutputStream(OutputStream out) throws IOException构造传入输出的对象
public final void writeObject(Object obj) throws IOException普通输出对象

ObjectInputStream类常用方法

方法类型描述
public ObjectInputStream(InputStream in) throws IOException构造构造输入对象
public final Object readObject() throws IOException,ClassNotFoundException普通从指定位置读取对象
package cn.uihtml.demo;
 class JavaDemo {
     public static final File SAVE_FILE = new File("D:" + File.separator + "uihtml.txt");
     public static void main(String[] args) throws Exception {
         saveObject(new Member("蜀国国主-->刘备"));
         System.out.println(loadObject());
     }
     public static void saveObjec(Object obj) throws Exception {
         ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(SAVE_FILE));
         oos.wirteObject(obj);
         oos.close();
     }
     public static Object loadObject() throws Exception {
         ObjectInputStream ois = new ObjectInputStream(new FileInputStream(SAVE_FILE));
         Object obj = ois.readObject();
         ois.close();
         return obj;
     }
 }

transient 关键字

默认情况下,当执行对象序列化的时候,会将类中的全部属性的内容进行序列化操作,但有些属性可能并不需要进行序列化的处理,这个时候可以在属性定义上使用transient关键字来完成了。

原创文章,作者:ZERO,如若转载,请注明出处:https://www.edu24.cn/course/java/java-i-o-action.html

Like (0)
Donate 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
ZEROZERO
Previous 2020年12月16日
Next 2020年12月24日

相关推荐

  • Java自学之类与对象

    定义 类是由成员属性和方法组成。成员属性主要定义类的一个具体信息,实际上一个成员属性就是一个变量,而方法是一些操作的行为。类的定义基础语法如下。 一个类定义完成后并不能够被直接使用…

    2020年11月25日
    1.1K
  • Java自学之多线程编程

    多线程编程是Java语言最为重要的特性之一。利用多线程技术可以提升单位时间内的程序处理性能,也是现代程序开发中高并发的主要设计模式。 进程与线程 进程是一个应用程序。线程是一个进程…

    2020年12月16日
    1.4K
  • spring boot练习篇之用户登录系统【接入数据库】

    抛弃JSP,只做纯粹的前后端分离项目。 写在前面 学习基础知识是枯燥无味的,之所以会这样,多数是因为心不静,对于如何运用它,感到茫然。所以建议大家在学习Java基础知识的时候,一定…

    2021年5月28日
    1.1K
  • spring4.x学习之用户登录与注册

    在之前的文章中我已经把后端工程项目创建好了,接下来就是编写项目了。 首先,我先创建一个数据库。数据库使用的是MySQL,数据库管理工具用的是Navicat。 打开数据库管理工具Na…

    2019年3月21日
    1.8K
  • Java自学之继承

    在面向对象的设计过程中,类是基本的逻辑单位。但是对于这些基本的逻辑单位需要考虑到重用的设计问题,所以在面向对象的设计里提供有继承,并利用这一特点实现类的可重用性定义。 类继承定义 …

    2020年12月3日
    1.2K
  • Java自学之数组

    在Java中数组是一组相关变量的集合,属于引用数据类型。 定义 数组引用传递分析 数组属于引用数据类型,在数组使用时需要通过关键字new开辟堆内存空间,一块堆内存空间也可以同时被多…

    2020年11月26日
    1.1K
  • JavaWeb入门案例之用户注册

    前言 之前把Java的基础知识系统的过了一遍,目前总算可以看懂Java代码了,接下来就是要学习Java开发框架(主要是springMVC)。 下面用一个用户注册的小案例,来总结一下…

    2021年1月13日
    1.4K
  • JAVA学习路线之夯实基础

    第一章 开发环境 JDK(Java SE Development Kit),Java标准版开发包,提供编译、运行Java程序所需的各种工具和资源,包括Java编译器、Java运行环…

    2020年1月14日
    1.5K
  • MyBatis之MyBatis-Generator标签配置及意义

    DTD 标签 <generatorConfiguration/>: 根标签,所有的配置都必须在该标签内配置;没有属性 <properties/>: 主要引用外部的pro…

    2019年12月27日
    1.7K
  • spring4.x学习之创建工程

    断断续续学习Java有两三个月了,目前还是处于入门阶段。关于java及spring那些的设计理念方面的理论知识,不花费大量精力及时间是看不懂的(至少对于我这么一个前端转后端的初学者…

    2019年3月19日
    1.7K