一:基本概念:
i:input输入(读取)
o:output输出(写入)
流:数据(字符,字节)。1个字符=2个字节,一个字节=8个二进制位。
输入:把硬盘中的数据,读取到内存中使用。
输出:把内存中的数据,写入硬盘中保存。
IO流分类:字符输入流(Reader),字符输出流(Writer),字节输入流(InputStream),字节输出流(OutputStream)。
二:File类的使用
(1)基础:
java.io.File类:文件和文件目录路径的抽象表示形式,与平台无关。
File能新建、删除、重命名文件和目录,但File不能访问访问文件内容本身。如果需要访问文件内容本身,则需要使用输入/输出流。
想要在JAVA程序中表示一个真实存在的文件或目录,那么必须有一个File对象,但是JAVA程序中的一个File对象,可能没有一个真实存在的文件或目录。
File对象可以作为参数传递给流的构造器。
(2)File类的常用构造器
import java.io.File;/*** File类的使用** 1.File类的一个对象,代表一个文件或一个文件目录(俗称:文件夹)* 2.File类声明在java.io包下* 3.File类中涉及到关于文件或文件目录的创建、删除、重命名、修改时间、文件大小等方法,* 并未涉及到写入或读取文件内容的操作。如果需要读取或写入文件内容,必须使用IO流来完成。* 4.后续File类的对象常会作为参数传递到流的构造器中,指明读取或写入的“终点”。*//*** File类的常用构造器** 1.public File(String pathname);* 以pathname为路径创建File对象, 可以是绝对路径或者相对路径,如果pathname是相对路径,则默认的当前路径在系统属性user.dir中存储。* 绝对路径:是一个固定的路径,从盘符开始。* 相对路径:是相对于某个位置开始。* 2.public File(String parent,String child);* 以parent为父路径,child为子路径创建File对象。* 3.public File(File parent,String child);* 根据一个父File对象和文件路径创建File对象。*/public class FileTest {public static void main(String[] args) {//构造器1File file1 = new File("hello.txt");//相对于当前moduleFile file2 = new File("D:\\hgk111\\abc.txt");//构造器2File file3 = new File("D:\\hgk1","aaa");//构造器3File file4 = new File(file3,"bbb.txt");}}
(3)File类中的常用方法
/*** 一:File类的获取功能* 1.public String getAbsolutePath();获取绝对路径* 2.public String getPath();获取路径* 3.public String getName();获取名称* 4.public String getParent();获取上层文件目录路径,若无,返回null* 5.public long length();获取文件长度(即字节数)。不能获取目录的长度* 6.public long lastModified();获取最后一次的修改时间,毫秒值* 7.public String[] list();获取指定目录下的所有文件或者文件目录的名称数组* 8.public File[] listFiles():获取指定目录下的所有文件或者文件目录的File数组* 二:File类的重命名功能* public boolean renameTo(File dest):把文件重命名为指定的文件路径.* 例如,file1.renameTo(file2)* 要想保证返回true,需要保证file1在硬盘中是存在的,且file2不能在硬盘中存在。* 三:File类的判断功能* 1.public boolean isDirectory();判断是否是文件目录* 2.public boolean isFile();判断是否是文件* 3.public boolean exists();判断是否存在* 4.public boolean canRead();判断是否可读* 5.public boolean canWrite();判断是否可写* 6.public boolean isHidden();判断是否隐藏*/
public boolean createNewFile()://真正的在硬盘中创建文件。若文件存在,则不创建,返回false。public boolean mkdirs()://创建文件目录。如果此文件目录存在,就不创建了。如果上层文件目录不存在,也不创建了。public boolean mkdirs()://创建文件目录。如果上层文件目录不存在,一并创建。创建注意事项:如果创建文件或者文件目录没有写盘符,那么,默认在项目路径下。public boolean delete()://删除文件或者文件夹删除注意事项:java中的删除不走回收站。要删除一个文件目录,请注意该文件目录内不能包含文件或者文件目录。
三:IO流原理及流的分类
(1)原理:
- I/O是Input/Output的缩写,I/O技术是非常实用的技术,用于处理设备之间的数据传输。如读/写文件、网络通讯等。
- JAVA程序中,对于数据的输入/输出操作以“流(Stream)”的方式进行。
- java.io包下提供了各种“流”类和接口,用以获取不同种类的数据,并通过标准的方法输入或输出数据。
- 输入input:读取外部数据(磁盘、光盘等存储设备的数据)到程序(内存)中。
输出output:将程序(内存)数据输出到磁盘、光盘等存储设备中。
(2)流的分类
按操作数据单位不同分为:字节流(8 bit),字符流(16 bit)
- 按数据流的流向不同分为:输入流、输出流
- 按流的角色不同分为:节点流、处理流
(3)流的体系结构
抽象基类 节点流(或文件流) 缓冲流(处理流)InputStream FileInputStream BufferedInputStreamOutputStream FileOutputStream BufferedOutputStreamReader FileReader BufferedReaderWriter FileWriter BufferedWriter
四:节点流(或文件流)
(1)FileReader读入数据的基本操作
/*** 将io下的hello.txt文件内容读入程序中,并输出到控制台* 1.read():返回读入的一个字符,如果达到文件末尾,返回-1.* 2.为了保证流资源一定可以执行关闭操作,需要执行try-catch-finally处理。* 3.读入的文件一定要存在,否在就会报“文件不存在”异常。*/public static void test(){FileReader fr = null;try {//1.实例化File类对象,指明要操作的文件File file = new File("D:\\hello.txt");//2.提供具体的流fr = new FileReader(file);//3.数据的读入//3.1--read():返回读入的一个字符,如果达到文件末尾,返回-1./* int data;while ((data=fr.read()) != -1){System.out.print((char) data);}*///3.2--对read()操作升级:使用read的重载方法char[] cbuf = new char[1024];//字符数组//byte bytes = new byte[1024];//字节数组int len;//read(char[] cbuf):返回每次读入到cbuf数组中的字符的个数,如果达到文件末尾,返回-1.while((len = fr.read(cbuf)) != -1){System.out.println(new String(cbuf,0,cbuf.length));}} catch (IOException e) {e.printStackTrace();}finally {//4.关闭流try {//以防File并没有被实例化if (fr != null){fr.close();}} catch (IOException e) {e.printStackTrace();}}}
(2)FileWriter写出数据的操作
/*** 从内存中写出数据到硬盘的文件里* 说明:* 1.如果文件不存在,在输出的过程中,会自动创建此文件。* File对应的硬盘文件如果存在,* 如果流使用的构造器是:FileWriter(file,false)/FileWriter(file),对原有文件的进行覆盖* 如果流使用的构造器是:FileWriter(file,true):不会对原有文件覆盖,而是在原有的基础上追写*/public static void testFileWriter() {//1.提供File类的对象,指明写到的文件FileWriter fw = null;try {File file = new File("hello1.txt");//2.提供FileWriter的对象,用于数据的写出fw = new FileWriter(file);//3.写出的操作fw.write("I hava a Dream!!!\n");fw.write("我有一个梦想!!!");} catch (IOException e) {e.printStackTrace();} finally {//4.流资源的关闭if (fw!=null){try {fw.close();} catch (IOException e) {e.printStackTrace();}}}}
(3)使用FileReader和FileWriter实现文本复制
public static void testFileReaderFileWriter() {FileReader fr = null;FileWriter fw = null;try {//1.创建File对象,指明读入和写出的对象File file1 = new File("hello1.txt");File file2 = new File("hello2.txt");//2.创建输入流和输出流对象fr = new FileReader(file1);fw = new FileWriter(file2, true);//在原文件后面追加续写//3.数据的读入和写出操作char[] chars = new char[1024];int len;while ((len = fr.read(chars)) != -1) {//每次写出len个字符fw.write(chars, 0, len);}}catch (IOException e){e.printStackTrace();}finally {//4.关闭流资源try {if (fw != null){fw.close();}}catch (IOException e){e.printStackTrace();}try {if (fr != null){fr.close();}}catch (IOException e){e.printStackTrace();}}}
五:缓冲流
/*** 案例:使用字节缓冲流实现非文本文件的复制.* 缓冲流的作用* 1.提高流的读取、写入的速度* 提高读写速度的原因:内部提供了一个缓冲区。* 2.处理流:就是“套接”在已有的流的基础之上。*/public static void BufferedStreamTest(){BufferedInputStream bis = null;BufferedOutputStream bos = null;try {//1.创建File对象,指明读入和写出的对象File file1 = new File("D:\\测试\\小说.zip");File file2 = new File("D:\\测试\\小小说1.zip");//2.造流//2.1:创建字节流FileInputStream is = new FileInputStream(file1);FileOutputStream os = new FileOutputStream(file2);//2.2:创建缓冲流bis = new BufferedInputStream(is);bos = new BufferedOutputStream(os);//3.数据的读入和写出操作byte[] bytes = new byte[1024];int len;while ((len = bis.read(bytes)) != -1) {//每次写出len个字符bos.write(bytes, 0, len);}}catch (IOException e){e.printStackTrace();}finally {//4.关闭流资源//要求:先关闭外层的流,再关闭内层的流//说明:关闭外层流的同时,内层流也会自动的进行关闭,因此关于内层流的关闭,可以省略try {if (bos != null){bos.close();}}catch (IOException e){e.printStackTrace();}try {if (bis != null){bis.close();}}catch (IOException e){e.printStackTrace();}}}
/*** 案例:使用字符缓冲流实现文本文件的复制.*/public static void BufferedReaderWriterTest(){BufferedReader br = null;BufferedWriter bw = null;try {//1.造流br = new BufferedReader(new FileReader(new File("D:\\测试\\1.txt")));bw = new BufferedWriter(new FileWriter(new File("D:\\测试\\3.txt")));//2.数据的读入和写出操作//方式一:使用char[]数组/*char[] chars = new char[1024];int len;while ((len = br.read(chars)) != -1) {//每次写出len个字符bw.write(chars, 0, len);}*///方式二:使用StringString data;//readLine():字符缓冲流中的方法,一次读取一行while ((data=br.readLine())!=null){bw.write(data+"\n");//data中不包含换行符bw.newLine();//提供换行的操作}}catch (IOException e){e.printStackTrace();}finally {//3.关闭资源try {if (br != null){br.close();}}catch (IOException e){e.printStackTrace();}try {if (bw != null){bw.close();}}catch (IOException e){e.printStackTrace();}}}
六:转换流
字节流中的数据都是字符时,转成字符流操作更高效。
很多时候我们使用转换流来处理文件乱码问题,实现编码和解码的功能。
/*** 处理流之二:转换流(属于字符流)* 1.作用:* 转换流提供了在字节流和字符流之间的转换。* 2.类型:* InputStreamReader:将InputStream转换为Reader(解码)* OutputStreamWriter:将Writer转换为OutputStream(编码)* 3.解码:字节、字节数组 ---> 字符数组、字符串* 编码:字符数组、字符串 ---> 字节、字节数组* 4.字符集:* 编码表的由来:计算机之只能识别二进制数据,早期由来是电信号,为了方便应用计算机,让它可以识别各个国家的* 的文字。就将各个国家的文字用数字来表示。并一一对应,形成一张表,这就是编码表。* 常见的编码表:* ASCLL:美国标准信息交换码,用一个字节的7位可以表示。* GBK:中国的中文编码表,最多两个字节编码所有字符* UTF-8:变长的编码方式,可用1-4个字节来表示一个字符。**/public class InputStreamReaderTest {public static void main(String[] args) {test1();}public static void test1(){InputStreamReader isr = null;OutputStreamWriter osw = null;try {FileInputStream fis = new FileInputStream("D:\\测试\\故事.txt");isr = new InputStreamReader(fis,"utf-8");//如果第二个参数不写,则使用系统默认的字符集,utf-8.FileOutputStream fos = new FileOutputStream("新的故事.txt");osw = new OutputStreamWriter(fos,"gbk");//根据什么选择用什么字符集解码?这要根据当初文本文件当初存的时候用的什么字符集编码。//读、写操作char[] chars = new char[200];int len;while ((len=isr.read(chars))!=-1){System.out.println(new String(chars,0,len));osw.write(chars,0,len);}} catch (IOException e) {e.printStackTrace();} finally {if (isr != null){try {isr.close();} catch (IOException e) {e.printStackTrace();}}if (osw != null){try {osw.close();} catch (IOException e) {e.printStackTrace();}}}}
七:标准输入、输出流
/*** 标准的输入、输出流:* 1:* System.in:标准的输入流,默认从键盘输入* System.out:标准的输出流,默认从控制台输出* 2:* System类的setIn(InputStream is)/setOut(OutputStream os)方式重新指定输入和输出的流。* 3:练习* 从键盘输入字符串,要求将读取到的整行字符串转换成大写输出,然后继续进行输入操作,直到输入“e"或者"exit"时,退出程序。* 方式一:使用Scanner实现,调用next()返回一个字符串。* 方式二:使用System.in实现。* System.in --> 转换流 ——> BufferedReader的readLine().*/public static void test1(){BufferedReader br = null;try {InputStreamReader isr = new InputStreamReader(System.in);br = new BufferedReader(isr);while (true){System.out.println("请输入字符串:");String data = br.readLine();if ("e".equalsIgnoreCase(data) || "exit".equalsIgnoreCase(data)){System.out.println("程序结束!");break;}String s = data.toUpperCase();System.out.println(s);}} catch (IOException e) {e.printStackTrace();} finally {try {if (br != null){br.close();}} catch (IOException e) {e.printStackTrace();}}}
八:打印流
/*** 打印流:* 实现将基本数据类型的数据格式转化为字符串输出* 打印流:PrintStream 和 PrintWriter* 提供了一系列重载的print()和println()方法,用于多种数据类型的输出。*/System.SetOut();重新指定一个位置,打印到那里
九:数据流
/*** 数据流:* 1.DataInputStream和DataOutputStream* 2.作用:用于读取或写出基本数据类型的变量或字符串* 3.注意点:读取不同类型的数据要与当初写入文件时保存的数据的顺序一致!!**/public static void test1(){DataOutputStream dos = null;DataInputStream dis = null;try {dos = new DataOutputStream(new FileOutputStream("D:\\abc.txt"));dis = new DataInputStream(new FileInputStream("D:\\abc.txt"));//写数据dos.writeUTF("哈哈哈");dos.flush();dos.writeInt(100);dos.flush();dos.writeBoolean(true);dos.flush();//读数据String name = dis.readUTF();int age = dis.readInt();boolean isMale = dis.readBoolean();System.out.println("name=" +name);System.out.println("age=" +age);System.out.println("isMale=" +isMale);} catch (IOException e) {e.printStackTrace();} finally {try {if (dos!=null){dos.close();}} catch (IOException e) {e.printStackTrace();}}try {if (dis!=null){dis.close();}} catch (IOException e) {e.printStackTrace();}}
十:对象流
/*** 对象流:ObjectInputStream;ObjectOutputStream* 1.作用:用于存储和读取基本数据类型数据或对象的处理流,它的强大之处就是可以把Java中的对象写入到数据源中,也能把对象从数据源中还原回来。* 2.注意:ObjectInputStream和ObjectOutputStream不能序列化static和transient修饰的成员变量。* 3.对象需要满足什么条件,才能被序列化?* (1)需要实现接口:Serializable接口。* (2)需要提供一个全局常量:serialVersionUID* 如:public static final long serialVersionUID=478529578257275L;* (3)除了当前的要序列化的类需要实现Serializable接口之外,还必须保证其内部所有属性也必须是可序列化的。* 默认情况下,基本数据类型也是可序列化的。* 4.序列化机制(重点)* 对象序列化机制允许把内存中的Java对象转换成平台无关的二进制流,从而允许把这种二进制流持久的保存在磁盘上,或通过网络将这种二进制流传输到另一个网络节点。当其他程序获取了这种二进制流,就可以恢复成原来的Java对象。*/public class ObjectInOutputStream {public static void main(String[] args) {test1();test2();}/*** 序列化过程:用ObjectOutputStream类保存基本数据类型或对象的机制。* 换句话说,就是将内存中的java对象保存到磁盘中或通过网络传输出去。*/public static void test1(){ObjectOutputStream oos = null;try {oos = new ObjectOutputStream(new FileOutputStream("D:\\ccc.txt"));oos.writeObject(new String("给我一首歌的时间。"));oos.flush();//刷新操作} catch (IOException e) {e.printStackTrace();} finally {if (oos != null){try {oos.close();} catch (IOException e) {e.printStackTrace();}}}}/*** 反序列化:用ObjectInputStream类读取基本数据或对象的机制。* 换句话说,就是将磁盘文件中的对象还原为内存中的一个java对象。*/public static void test2(){ObjectInputStream ois = null;try {ois = new ObjectInputStream(new FileInputStream("D:\\ccc.txt"));Object o = ois.readObject();String str = (String)o;System.out.println(str);} catch (IOException | ClassNotFoundException e) {e.printStackTrace();} finally {if (ois != null){try {ois.close();} catch (IOException e) {e.printStackTrace();}}}}}
