Java的IO基本操作 1

1File

File可以理解为文件和文件夹(目录),用于表示磁盘中某个文件或文件夹的路径。该类包含了文

件或者文件夹的创建、删除、重命名、判断是否存在等方法。

只能获取和设置文件本身的信息(文件大小,是否可读),不能设置和获取文件里面的内容。

Unix/Linux/Mac:  严格区分大小写,使用”/”来表示路径分隔符。

Windows: 默认情况下是不区分大小写的,使用”\”来分割目录路径。但是在Java中一个”\”表示转

义,所以在Windows系统中就得使用两个”\\”

操作File常见方法:

String getName():获取文件名称

String getPath():获取文件路径

String getAbsolutePath():获取绝对路径

File getParentFile():获取上级目录

boolean exists():判断文件是否存在

boolean isFile() :是否是文件

boolean isDirectory():判断是否是目录

boolean delete() :删除文件

boolean mkdirs():创建当前目录和上级目录

File[] listFiles() :列出所有文件对象

public class FileDemo {

    public static void main(String[] args) throws Exception {

        File f = new File("C:/test/123.txt");

        System.out.println(f.getName());//123.txt

        System.out.println(f.getPath());//C:/test/123.txt

        System.out.println(f.getAbsolutePath());//C:/test/123.txt

        System.out.println(f.getParentFile().getName());//test

        System.out.println(f.exists());//true

        System.out.println(f.isFile());//true

        System.out.println(f.isDirectory());//false

        //如果当前文件的父文件夹不存在,则创建

        if(!f.getParentFile().exists()) {

            f.getParentFile().mkdirs();

        }

        //列出当前文件夹中所有文件

        File[] fs = f.getParentFile().listFiles();

        for (File file : fs) {

            System.out.println(file);

        }

    }

}

列出给定目录中的全部文件的路径,包括给定目录下面的所有子目录。

public class FileDemo2 {

public static void list(File file) {

if (file.isDirectory()) {

System.out.println(file.getPath());

// 如果是文件夹,则继续列出

File[] fs = file.listFiles();

if (fs != null) {

for (File f : fs) {

list(f);

  }

  }

  }

System.out.println(file);

  }

public static void main(String[] args) {

 // 需求:给定一个目录(test),遍历其下的所有目录(包含子目录)和文件

File file = new File("h:\\test");

list(file);

  }

}

2、字符编码

2.1、字符编码发展历程

阶段一:计算机在美国等发达国家起步

计算机只认识数字(01),在计算机里一切数据都是以数字来表示,因为英文符号有限,所以规定

使用的字节的最高位是0。每一个字节都是以0~127之间的数字来表示,比如A对应65a对应97。此时

把每一个字节按照顺序存放在一张表格中,这就是美国标准信息交换码——ASCII编码表

阶段二:其他国家的普及

随着计算机在全球的普及,很多国家和地区都把自己的字符引入了计算机,比如汉字。此时发现一

个字节(128个)能表示数字范围太小,而汉字太多,128个数字不能包含所有的中文汉字,那么此时就

规定使用两个字节一起来表示一个汉字

规定:原有的ASCII字符的编码保持不变,仍然使用一个字节表示,为了区别一个中文字符与两个ASCII

码字符,中文字符的每个字节最高位(符号位)规定为1(中文的二进制是负数),该规范就是GB2312

编码表。后来在GB2312码表的基础上增加了更多的中文汉字,也就出现了更强大的GBK码表。

阶段三:互联网发展

中国人是认识汉字的,现在需要和外国人通过网络交流,此时需要把把汉字信息传递给外国人,但

外国的码表中没有收录汉字,此时就会把汉字显示为另一个符号甚至不能识别的乱码。为了解决各个国

家因为本地化字符编码带来的影响,就干脆把全世界所有的符号统一收录进Unicode编码表。

如果使用Unicode码表,那么某一个字符在全世界任何地方都是固定的。比如''这个字,在任何地方都

是以十六进制的54E5来表示,因此说Unicode是国际统一编码

Unicode字符集https://unicode-table.com/cn/blocks/

2.2、常见的字符编码和操作

常见的字符集

ASCII:占一个字节,只能包含128个符号。不能表示汉字。

ISO-8859-1:也称之为latin-1,占一个字节,只收录西欧语言,不能表示汉字。

GB2312/GBK/GB18030:占两个字节,支持中文。

ANSI:占两个字节,在简体中文的操作系统中ANSI 就指的是 GBK

UTF-8:是一种针对Unicode的可变长度字符编码,是Unicode的实现方式之一,支持中文。在开

发中建议使用。

UTF-8 BOM:是微软搞出来的一种编码,不要使用。

存储字母、数字、汉字的常识:

存储字母和数字无论是什么字符集都占1个字节.

存储汉字,GBK家族占两个字节,UTF-8家族占3个字节。

不能使用单字节的字符集(ASCIIISO-8859-1)来存储中文,否则会乱码。

2.3、字符的编码和解码操作

数据在网络上传输是以二进制的格式,二进制格式就是byte数组,此时需要把信息做编码和解码处理。

编码:把字符串转换为byte数组  String--->byte[]

解码:把byte数组转换为字符串  byte[]--->String

注意:一定要保证编码和解码的字符集相同,才能正确解码出信息。

经典案例:在表单中填写中文,为什么在服务端看到的是乱码问题。

情景分析,比如浏览器使用UTF-8编码,服务器使用ISO-8859-1解码。

此时编码和解码的字符类型不同,那么乱码就出现了。

先来分析乱码产生的原因:

乱码的解决方案:

public class CodeDemo {

    public static void main(String[] args) throws Exception {

        String input = "龙哥";//模拟用户输入的中文数据

        // 编码操作:String -> byte[]

        byte[] data = input.getBytes("UTF-8");

        System.out.println(Arrays.toString(data));//[-23, -66, -103, -27, -109,

-91]

        // 解码操作:byte[] -> String

        // 因为服务器时老外写的,老外在解码的时候使用ISO-8859-1,此时就乱码了

        String ret = new String(data, "ISO-8859-1");

        System.out.println(ret);//输出:龕啥  

//---------------------------------------------

        // 解决方案:重新对乱码编码回到byte[],重新按照UTF-8解码

        data = ret.getBytes("ISO-8859-1");

        System.out.println(Arrays.toString(data));//[-23, -66, -103, -27, -109,

-91]

        ret = new String(data,"UTF-8");

        //---------------------------------------------

        System.out.println(ret);//输出:龙哥

    }

}

IO流操作

1IO流概述

1.1IO概述(了解)

什么是IOInputOutput,即输入和输出。

电脑相关的IO设备:和电脑通信的设备,此时要站在电脑的角度,把信息传递给电脑叫输入设备,把电

脑信息传递出来的叫输出设备。

输入设备:键盘、鼠标、麦克风、扫描器等

输出设备:显示器、打印机、投影仪、耳机、音响等

为什么程序需要IO呢?

案例1:打游戏操作,需要存储游戏的信息(保存副本)。

此时需要把游戏中的数据存储起来,数据只能存储在文件中。

案例2:打游戏操作,需求读取之前游戏的记录信息,数据存储在一个文件中的。

此时游戏程序需要去读取文件中的数据,并显示在游戏中。

流的概念

(stream)是指一连串流动的数据单元(字符、字节等),是以先进先出方式发送信息的通道。

IO流操作是一个相对的过程,一般的,我们在程序角度来思考(程序的内存)。

程序需要读取数据:文件——>程序,输入操作

程序需要保存数据:程序——>文件,输出操作

1.2IO操作示意图

讲解IO知识点的时候,习惯和生活中的水流联系起来,一起来看看复古的水井和水缸。

此时站在水缸的角度,分析IO的操作方向:

输入操作:水井——>水缸

输出操作:水缸——>饭锅

注意:谁拥有数据,谁就是源,把数据流到哪里,哪里就是目标。那么,请问水缸是源还是目标。

1.3、流的分类

根据流的不同特性,流的划分是不一样的,一般按照如下情况来考虑:

流动方向:分为输入流和输出流

数据传输单位:分为字节流和字符流,即每次传递一个字节(byte)或一个字符(char

字符和字节是什么关系?

一个字符按照字符集可以编码成多个字节

功能上划分:分为节点流和处理流,节点流功能单一,处理流功能更强  (下节课)。

流的流向是相对的,我们一般站在程序的角度:

程序需要数据 把数据读进来 →  输入操作(read):读进来

程序保存数据 把数据写出去     输出操作(write):写出去

六字箴言:读进来,写出去(仔细揣摩这六个字有什么高深的含义)

2、四大基流 

流向

字节流(单位是字节)

字符流(单位是字符)

Reader ( 字符输入流 )

Writer ( 字符输出流 )

输入流

输出流

InputStream( 字节输入流 )

OutputStream ( 字节输出流 )

操作IO流的模板:

1):确定源或者目标对象(挖井).

输入操作: 把文件中的数据流向到程序中,此时文件是源,程序是目标.

输出操作: 把程序中的数据流向到文件中,此时文件是目标,程序是源.

2):创建IO流对象(水管).

输入操作: 创建输入流对象.

输出操作: 创建输出流对象.

3):具体的IO操作.

输入操作: 输入流对象的read方法.

输出操作: 输出流对象的write方法.

4):关闭资源(勿忘). 一旦资源关闭之后,就不能使用流对象了,否则报错.

输入操作: 输入流对象.close();

输出操作: 输出流对象.close();

注意:

四大抽象流是不能创建对象的,一般的我们根据不同的需求创建他们不同的子类对象,比如操作文

件时就使用文件流。

不管是什么流,操作完毕都必须调用close方法,释放资源。

3、字节输入流/字节输出流

3.1InputStream(字节输入流)

InputStream 表示字节输入流的所有类的父类。

InputStream 常用方法

方法

方法作用

abstract int

read()

从输入流中读取一个字节数据并返回该字节数据,如果到达流的末尾,则返

 -1

int read(byte[]

buff)

从输入流中读取多个字节数据,并存储在缓冲区数组 buff 中。

返回已读取的字节数量,如果已到达流的末尾,则返回 -1

关闭此输入流并释放与该流关联的所有系统资源。

InputStream  close 方法不执行任何操作。

void close()

3.2OutputStream(字节输出流)

OutputStream 表示字节输出流的所有类的超类。

OutputStream常用方法:

方法

方法作用

abstract void write(int b)

write(byte[] buff)

write(byte[] b, int off,int len)

void close()

将指定的一个字节数据b写入到输出流中。

把数组buff中所有字节数据写入到输出流中。

把数组buff中从索引off 开始的len 个字节写入此输出流中。

关闭此输出流并释放与此流有关的所有系统资源。

InputStream/OutputStream 只定义了流的流向和流通道的数据单元,并没有定义数据源和目的地,

java.io包中的类是按照源数据源和目的地进行划分的。

java.io包中的具体的流操作类命名规则:数据源/目的地 + 数据传输单元(流向)

例如 : File + InputStream /  File + OutputStream

3.3、文件字节流 

当程序需要读取文件中的数据或者把数据保存到文件中去,此时就得使用文件流,但是注意只能操作纯

文本文件(txt格式),不要使用WordExcel。文件流比较常用。

需求1:使用文件字节输入流,读取a.txt文件中的数据

public class FileInputStreamDemo1 {

public static void main(String[] args) throws IOException {

// 需求:使用文件字节输入流,b.txt文件中的数据读取到程序中

    /**

 * 分析:

 * 数据源:文件 File

 * 流向: 输入流 Input

 * 传输单元:字节 Stream  => FileInputStream

 */

// step 1: 确定数据源

File file = new File("G:\\test\\b.txt");

// step 2: 建立管道

FileInputStream in = new FileInputStream(file);

// step 3: 读取操作(一次读取一个)

int b = 0;

b = in.read(); // h

b = in.read(); // e

b = in.read(); // l

b = in.read(); // l

b = in.read(); // o

// 已经读到末尾,返回-1

c = in.read();   // -1

System.out.println(c);

// step 4: 关闭操作

in.close();

  }

}

-----------------------------------------------------------------------------

 public class FileInputStreamDemo2 {

public static void main(String[] args) throws IOException {

// 需求:使用文件字节输入流,b.txt文件中的数据读取到程序中

// step 1: 确定数据源

File file = new File("G:\\test\\b.txt");

// step 2: 建立输入流管道( 创建具体的IO流对象 )

FileInputStream in = new FileInputStream(file);

// step 3: 操作IO

// 一次读取一个字节

int b;

while ( (b=in.read()) != -1 ) {

System.out.println((char)b);

  }

// step 4: 关闭管道

in.close();

  }
}

--------------------------------------------------------------------------------

 public class FileInputStreamDemo3 {

public static void main(String[] args) throws IOException {

                // 需求:使用文件字节输入流,b.txt文件中的数据读取到程序中

// step 1: 确定数据源

File file = new File("G:\\test\\b.txt");

// step 2: 建立输入流管道( 创建具体的IO流对象 )

FileInputStream in = new FileInputStream(file);

// step 3: 操作IO

// 一次读取多个字节

byte[] buf = new byte[2]; // 缓存数组

int len; // 表示读取的有效字节的个数

StringBuilder sb = new StringBuilder();

while( (len = in.read(buf)) != -1 ) {

String str = new String(buf,0,len);

sb.append(str);

  }

System.out.println(sb.toString());

// step 4: 关闭管道

in.close();

  }

}

需求2:使用文件字节输出流,把程序中数据保存到b.txt文件(先只操作英文)

public class Test01FileOutputStream {

public static void main(String[] args) throws IOException {

// step 1: 确定目的地(b.txt

File file = new File("G:\\test\\b.txt");

// step 2: 建立流管道(通过具体的IO流对象创建管道)

FileOutputStream out = new FileOutputStream(file);

// step 3: 操作IO

// 一次写入一个字节

/*out.write(97);

out.write(98);

out.write(99);*/

// 一次写入多个字节

String str = "hello";

byte[] buf = str.getBytes("UTF-8");

out.write(buf);

// step 4: 关闭管道

out.close();

  }

}

4、字符输入流/字符输出流

4.1Reader(字符输入流)

Reader表示所有字符输入流的父类。

常用方法

方法作用

abstract void

close()

关闭此输入流并释放与该流关联的所有系统资源。

从输入流中读取一个字符数据并返回该字符数据,如果到达流的末尾,则返

 -1

int read()

int read(char[]

cbuf)

从输入流中读取多个字符,并存储在缓冲区数组 cbuf 中。

返回已读取的字符数,如果已到达流的末尾,则返回 -1

4.2Writer(字符输出流)

 Writer 表示所有字符输出流的父类。

常用方法

方法作用

void write(int c)

将指定的一个字符数据c写入到输出流中。

把数组cbufcbuf.length 个字符数据写入到输出流

中。

void write(char[] cbuf)

abstract void write(char[] cbuf, int

off,int len)

把数组cbuf中从索引off 开始的len 个字符写入此输

出流中。

void write(String str)

abstract void close()

abstract void flush()

str字符串数据写入到输出流中。

关闭此输入流并释放与该流关联的所有系统资源。

刷新此输出流并强制写出所有缓冲的输出字符。

关于字符流Reader/Writer ,它们是抽象父类,只是规定了流的传输单元和流动方向,没有确定数据源

和目的地,所以,如果需要具体的读写操作,一定要找其子类,其子类明确了数据源和目的地。

子类的命名规则:数据源/目的地 + 流的传输单元和流动方向。

4.3、文件字符流 

需求1:使用文件字符输出流,把程序中数据保存到result2.txt文件,操作中文

public class Test01FileWriter {

public static void main(String[] args) throws IOException {

// step 1: 确定目的地

File file = new File("G:\\test\\d.txt");

// step 2: 建立管道

FileWriter writer = new FileWriter(file);

// step 3: 操作IO

// 一次写一个字符

/*writer.write('a');

writer.write('b');

writer.write('c');

writer.write('');*/

// 一次写多个字符

String str = "abc";

char[] cbuf = str.toCharArray();

writer.write(cbuf);

// writer.write(str);

// step 4: 刷新缓冲区,把字符一次性写入文件中

writer.flush();

// step 5: 关闭流通道(关闭流通道时,自动flush一次)

writer.close();

  }

}

注意:FileWriter 写入文件时,以平台默认字符集写入文本型文件。

需求2:使用文件字符输入流,读取result2.txt文件中的数据

public class Test03FileInputStream {

public static void main(String[] args) throws IOException {

// 需求:给定一个文件(a.txt),读取文件的内容到程序中。

// 1> 确定数据源

File file = new File("G:\\test\\a.txt");

// 2> 建立管道

FileReader reader = new FileReader(file);

// 3> 读取(一次读取一个字符)

int c;

StringBuilder sb = new StringBuilder();

while ( (c = reader.read()) != -1){

sb.append((char)c);

  }

System.out.println(sb.toString());

// 4> 关闭操作

reader.close();

  }

}

---------------------------------------------------------------------

public class Test04FileInputStream {

public static void main(String[] args) throws IOException {

// 需求:给定一个文件(a.txt),读取文件的内容到程序中。

// 1> 确定数据源

File file = new File("G:\\test\\a.txt");

// 2> 建立管道

FileReader reader = new FileReader(file);

// 3> 读取(一次读取多个字符到字符缓冲区)

char[] cbuf = new char[2];

int len;

StringBuilder sb = new StringBuilder();

while( (len = reader.read(cbuf)) != -1 ){

sb.append(cbuf,0,len);

  }

System.out.println(sb.toString());

// 4> 关闭操作

reader.close();

  }

}

字节流和字符流选用问题

使用记事本打开某个文件,如果可以看到内容的就是文本文件,否则可以暂时认为是二进制格式的。

一般的,操作二进制文件(图片、音频、视频等)必须使用字节流操作文本文件使用字符流,尤其是

操作带有中文的文件,使用字符流不容易导致乱码,因为使用字节流可能出现读取半个汉字的尴尬(汉

字由两个或三个字节组成)。当然,如果不清楚属于哪一类型文件,都可以使用字节流。

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值