IO
- 1 IO操作流stream
- 2 File磁盘文件操作
- 3 字节流(stream)
- 4 字符流(FileReader和FileWriter)
- 5 BufferedInputStream和BufferOutputStream(缓存机制)
- 6 DataInputStream和DataOutputStream(可以按数据类型输入输出)
- 7 相关转换操作
- 8 转换流InputFileReader和OutFileWriter(字符和字节之间的转换,指定格式进行读写)
- 9 对象操作流(读写到本地文件都是直接是字节,不让它转换)
- 11 java的输入和输出
- 12 知识点大总结
整个文件操作很简单,20分钟搞懂
1 IO操作流stream
不同输入输出设备之间的数据传输抽象为流
1.1 流就相当于一个流水线
1.1.1 filter(过滤每一个元素)
内部类——匿名方法——普通方法
1.1.2 其他中间方法
1.1.3 终结方法
1.1.4 不能修改原数据
###1.1.5 流数据保存
1.2 流分为字节流和字符流
根据流传输的数据类型:
- 字节流(以stream结尾);
- 字符流(以Reader和Writer结尾);
Java字节流用于执行8位字节的输入和输出,
而Java字符流用于执行16位unicode的输入和输出。尽管有许多与字符流相关的类,但最常用的类是FileReader和FileWriter。
尽管在内部FileReader使用FileInputStream和FileWriter使用FileOutputStream,但是这里的主要区别在于FileReader一次读取两个字节,而FileWriter一次写入两个字节。
1.2.1 文本文件
1.3 根据流的操作方式:
- 输入流(读取:从外界文件中读取数据到程序)
- 输出流(写入:从程序输出到文件中)
2 File磁盘文件操作
2.1 构造方法
2.2 相对路径
2.3 创建文件夹和文件
2.4 删除
2.5 判断文件是否存在
2.6 高级获取功能listfiles
2.6 案例1(创建文件)
2.7 案例2 (删除多级文件夹)
2.8 获取文件名和文件路径(3种方法)
// 获取文件名
package test;
import java.io.File;
public class FileName {
/**
* @param args
*/
public static void main(String[] args) {
// 举例:
String fName =" G:\\Java_Source\\navigation_tigra_menu\\demo1\\img\\lev1_arrow.gif ";
// 方法一:
File tempFile =new File(fName.trim());
String fileName = tempFile.getName();
System.out.println("fileName = " + fileName);
// 方法二:
String fName = fName.trim();
String fileName = fName.substring(fName.lastIndexOf("/")+1);
//或者
String fileName = fName.substring(fName.lastIndexOf("\\")+1);
System.out.println("fileName = " + fileName);
// 方法三:
String fName = fName.trim();
String temp[] = fName.split("\\\\"); /**split里面必须是正则表达式,"\\"的作用是对字符串转义*/
String fileName = temp[temp.length-1];
System.out.println("fileName = " + fileName);
}
}
2.9 获取文件名并且去掉后缀扩展名
public static String getFileNameWithoutSuffix(File file){
String fName =" G:\\Java_Source\\navigation_tigra_menu\\demo1\\img\\lev1_arrow.gif ";
File tempFile =new File(fName.trim());
String fileName = tempFile.getName();
System.out.println("fileName = " + fileName);
System.out.println(fileName.substring(0, fileName.lastIndexOf(".")));
}
3 字节流(stream)
3.1 字节流写入
3.2 字节流写数据的3种方式
只能对字节或字节数组操作
import java.io.*;
import java.util.Scanner;
public class test {
public static void main(String[] args) throws IOException {
//创建文件
File file = new File("G:\\file.txt");
if(!file.exists()){
file.createNewFile();
System.out.println(file.getName()+"文件已创建!");
}
//写入文件
try{
FileOutputStream fo = new FileOutputStream(file);
byte []buy = "今天你emo了吗?".getBytes();
fo.write(buy);
fo.close();
//读取文件
FileInputStream fi = new FileInputStream(file);
byte []byt = new byte[2014];
int len = fi.read(byt);//fi.read(byt)返回字节数组byt的字节数
System.out.println("文件的信息是:"+new String(byt,0,len));
fi.close();
}catch(Exception E){
E.printStackTrace();
}
}
}
3.3字符串转为字节+输出换行
3.4 标准写法加try_catch
3.5 读数据read
3.6 提高读写速度(用字节流数组,再进一步用字节缓冲流)
3.7 字节缓冲流(替代字节数组的方式提高读写效率)
相当于创建了一个长度为8192的字节数组
进一步缓冲流也可以加字节数组,效率更高
3.8 字节流读写文本文件中的中文会出现乱码,编码和解码不对应(编码表)
存储的时候是
中文——bytes数组(也就是数字)——二进制码
出现乱码程序和原因
== 解决方法,字符流读取的时候就不会有问题==
总结
3.9 码表
3.10 编码和解码
3.11 直接获取一个文件的字节数,全部读到数组(大文件如何读取)
3.11.1 全部文件读取到数组中
两种方法
一、使用path和files
Path path = Paths.get("file path");
byte[] data = Files.readAllBytes(path);
二、 使用字节流用数组读取全部
public static byte [] readWholeFile(String inpath){
File fi = new File(inpath);
// 这里可以默认是long,如果是int可能超出内存限制,work only for 2GB file, because array index can only up to Integer.MAX
System.out.println(fi.length()); // 得到文件大小,多少个byte,字节
byte [] buffer = new byte [( int )fi.length()];
FileInputStream f = null;
try {
f = new FileInputStream(inpath);
f.read(buffer);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
f.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return buffer;
}
3.11.2 大文件读取
java 分批次读取大文件的三种方法 - 名曰大神 - 博客园
3.12 FileInputStream经常出现的1个错误
在函数中调用F经常出现这个问题
编辑器提示
两种解决方案:
一是向上抛出异常,但是在其它地方调用这个函数的时候必须解决这个异常,用try,catch语句
二是直接在代码块中try-catch处理这个语句
public static byte [] readWholeFile(String inpath){
File fi = new File(inpath);
// 这里可以默认是long,如果是int可能超出内存限制,work only for 2GB file, because array index can only up to Integer.MAX
System.out.println(fi.length());
byte [] buffer = new byte [( int )fi.length()];
FileInputStream f = null;
try {
f = new FileInputStream(inpath);
f.read(buffer);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
f.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return buffer;
}
4 字符流(FileReader和FileWriter)
每次读取的是1个字符
字符流的底层是字节流+编码表实现的
4.1 读取字符(读1个和读1个数组和读一行)
4.2.1 读取1个字符
直接用read方法
4.2.2 读取1个字符数组
4.2.3 读取1行
File file = new File("D:/test.txt");
if(file.isFile() && file.exists()){
try {
FileInputStream in = new FileInputStream(file);
InputStreamReader reader = new InputStreamReader(in);
BufferedReader br = new BufferedReader(reader);
String line = null;
while ((line = br.readLine()) != null){
System.out.println(line);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}catch (IOException e) {
e.printStackTrace();
}
}
FileReader和FileWriter的具体使用方法和属性_迷途书生、的博客-CSDN博客
https://blog.csdn.net/weili222/article/details/109538527
4.2 写字符串
public static void readtxtChar() {
FileReader reader = null;
try {
reader = new FileReader("E:\\DoIt\\20220728熟悉操作\\a111111.txt");
//读取字符数据
System.out.println((char) reader.read());
int tmp = 0;
while ((tmp = reader.read()) != -1) {
System.out.println((char) tmp);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
//关闭流对象
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
4.3 刷新流(fiush,刷新到本地但是流没有关闭)
4.4 字符缓冲流(和字节缓冲流作用用法一样,一次读8192个字符,而不是1个了,加快速度)
4.5 字符换冲流特有方法
5 BufferedInputStream和BufferOutputStream(缓存机制)
BufferedInputStream和BufferedOutputStream_lidong777777的博客-CSDN博客
https://blog.csdn.net/lidong777777/article/details/125766047
6 DataInputStream和DataOutputStream(可以按数据类型输入输出)
很简单
3分钟搞懂
DataInputStream和DataOutputStream_鄙视土包子的博客-CSDN博客
https://blog.csdn.net/m0_47667419/article/details/106484484
7 相关转换操作
7.1 字符和字符串转换
char[] chs = new char[3];
int num = fr.read(chs);
//字符转字符串
System.out.println("num="+num+":"+new String(chs));
//字符串转为字符
String str=input.next();
char ss[] = str.toCharArray();//利用toCharArray方法转换
7.2 字符串和byte数组相互转换
7.2.1 字符串存的是字符不是16进制的字符
byte []buy = "今天你emo了吗?".getBytes();
String str = "Hello";
byte[] srtbyte = str.getBytes();
String res = new String(srtbyte);
System.out.println(res);
// byte数输出为16进制字符串
for (byte aByte : bytes) {
String x = Integer.toHexString(aByte);
}
package com.StringTest;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
public class StringToByte {
public static void main(String[] args) {
String str1 = "abc123";
//String转byte[]
byte[] bytes = str1.getBytes(StandardCharsets.UTF_8);
System.out.println(Arrays.toString(bytes));
//byte[]转String
String s = new String(bytes);
System.out.println(s);
}
}
Java中字符串和byte数组互相转换_ScriptGirl的博客-CSDN博客_java 字符串转字节数组
https://blog.csdn.net/qq_30885821/article/details/111947579
7.2.2 字符串存的是16进制的字符(就是16进制和10进制的转换,完全一样)
3种方法都可以
//将16进制表示的字符换转为10进制
h = "3f";
byte re= new BigInteger(h, 16).byteValue();
//
System.out.println(Integer.valueOf("F", 16));//16
//10进制的数转为16进制表示的字符串
String str = Integer.toHexString(CRC); //crc的校验码是4位的,转换为了16进制
System.out.println(Integer.toHexString(2));//2
System.out.println(Integer.toHexString(15));//f
System.out.println(Integer.toHexString(16));//10
// 字符串中存的是2个字符表示的16进制数,比如“6a72”,6a是106的16进制表示
public static byte[] hexStringToBytes(String hexString) {
if (hexString == null || hexString.equals("")) {
return null;
}
hexString = hexString.toUpperCase();
int length = hexString.length() / 2;
char[] hexChars = hexString.toCharArray();
byte[] d = new byte[length];
for (int i = 0; i < length; i++) {
int pos = i * 2;
d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));
}
return d;
}
/**
* Convert char to byte
* @param c char
* @return byte
*/
private byte charToByte(char c) {
return (byte) "0123456789ABCDEF".indexOf(c);
}
public byte[] preHandler(String param){
/**
* @Description: 将字符串转化为16进制数,由数字组成的字符串,两个字符表示1个字符串
* @param: [param]
* @return: byte[]
* @Date: 2018/6/12
*/
int len = param.length();
if (len%2 != 0) return null; // lx如果不是偶数就返回null,为什么
byte[] bytes = new byte[len/2]; // lx8位byte类型的数组
int times = 0;
// lx每次拿2个
for(int i = 0;i < len;i = i + 2){
String token = param.substring(i,i+2);
System.out.println(times + ":"+token);
//将16位的整数字符串转换为10位,两个字符在一起表示1个数,171超出了byte127的限制,会变为-85
byte b = (byte) Integer.parseInt(token, 16);
System.out.println("得到的b:"+b);
bytes[times] = b;
times++;
}
return bytes;
}
7.2.3 1个字节数据的16进制表示应该是两个字符却出现了fffffffc8个字符异常
Java中十六进制转换 Integer.toHexString()
https://blog.csdn.net/lisheng19870305/article/details/46343809
7.3 不同进制数之间的转换
7.3.1 不同进制数的定义
int CRC = 0x0000ffff;//16进制
int CRC = 00000ffff;//8进制
7.3.2 不同进制数的转换
正常打印输出啥的默认都是10进制的,如果想要显示为16进制等,需要用函数将10进制数转换为表示16进制的字符串。
7.3.2.1 10进制的整数转为其它进制表示的字符串
System.out.println("最终的校验码2进制:"+Integer.toBinaryString(CRC));
String str = Integer.toHexString(CRC); //crc的校验码是4位的,转换为了16进制
//若CRC最前数字为0,转为int会将0忽略。
if (str.length() == 3) {
str = "0" + str;
} else if (str.length() == 2) {
str = "00" + str;
} else if (str.length() == 1) {
str = "000" + str;
}
return str;
用java实现进制之间的相互转换
https://blog.csdn.net/qq_48627750/article/details/122388722
7.3.2.2 不同进制表示的字符串转为10进制表示的整数
public byte[] preHandler(String param){
/**
* @Description: 将字符串转化为16进制数,由数字组成的字符串,两个字符表示1个字符串
* @param: [param]
* @return: byte[]
* @Date: 2018/6/12
*/
int len = param.length();
if (len%2 != 0) return null; // lx如果不是偶数就返回null,为什么
byte[] bytes = new byte[len/2]; // lx8位byte类型的数组
int times = 0;
// lx每次拿2个
for(int i = 0;i < len;i = i + 2){
String token = param.substring(i,i+2);
System.out.println(times + ":"+token);
//将16位的整数字符串转换为10位,两个字符在一起表示1个数,171超出了byte127的限制,会变为-85
byte b = (byte) Integer.parseInt(token, 16);
System.out.println("得到的b:"+b);
bytes[times] = b;
times++;
}
return bytes;
}
// 2进制字符串转为10进制表示,也就是转换为整数
public static void main(String[] args) {
int a = Integer.parseInt("10100011", 2);
int b = Integer.parseInt("101010", 2);
System.out.println(a);
System.out.println(b);
System.out.println(a*256+b);
}
// 2进制转为整数的时候用int和byte是完全不一样的结果
public static void main(String[] args) {
int a = Integer.parseInt("10100011", 2);
String strA = Integer.toHexString(a);
byte b = (byte)Integer.parseInt("10100011", 2);
String strB = Integer.toHexString(b);
System.out.println(a);
System.out.println(strA);
System.out.println(b);
System.out.println(strB);
}
用int接说明输入的数是163,用byte接说明输入的数是-93,而且Integer.toHexString(b);方法实际上把参数转换为了整数,byte型变成了int型,所以得到的16进制结果是8位的。2个16进制表示8位,int型共32位,需要8个16进制表示。负数的时候它用32位的bit表示,第一位是1,整数的时候第一位是0,所以前面的0都会被忽略。
public static byte[] stringToByte(String content){
// 16进制表示的字符串转为byte数组
String[] arrString = content.split("\\s+");
byte[] dataMessage = new byte[arrString.length];
for(int i=0; i<5; i++){
dataMessage[i] = new BigInteger(arrString[i], 16).byteValue();
System.out.println("字符数组:"+arrString[i]);
System.out.println("byte数组:"+re);
}
return dataMessage;
}
7.3.3 java的byte数转2进制表示
java中正负数二进制表示,正码和反码:
https://blog.csdn.net/weixin_29053561/article/details/88653082
Java中byte类型的范围
https://blog.csdn.net/yuyonbbo/article/details/88696494
byte数的8位2进制表示
整数转化为8位二进制详解(包括正数和负数) 适用范围-127~+127_8位二进制转换
https://blog.csdn.net/Sunsetsunset/article/details/122705722
//下面这种写法是错误的,因为Integer.toBinaryString(bit8)自动把byte类型转换为了int类型,变成32位了,如果是整数没问题,但是负数就会显示的是32位而不是8位。
public static void main(String[] args) {
byte number = -2;
System.out.println(bit8Tobit6Arr(number));
}
public static String bit8Tobit6Arr(byte bit8){
String str = Integer.toBinaryString(bit8);
System.out.println(str);
int strLength = str.length();
switch (strLength){
case 1: str = "0000000" + str;
break;
case 2: str = "000000" + str;
break;
case 3: str = "00000" + str;
break;
case 4: str = "0000" + str;
break;
case 5: str = "000" + str;
break;
case 6: str = "00" + str;
break;
case 7: str = "0" + str;
break;
}
return str;
}
上面代码的输出:
如果输入的是整数没问题,比如输入4,输出结果为:
修改为:
7.4 10进制字符串和数字之间的转化(用Integer类)
String s = "222";
Integer i1 = Integer.valueOf(s);
Integer i2 = new Integer(s);
Integer i3 = Integer.parseInt(s);
// 以上三方法可将数字字符串转化为Integer数值型,得到整型的222
Integer i4 = s.charAt(0)-'0';
// 此方法可取数字字符串的具体某个数字的值,得到整形的2
Integer i5 = new Integer(s.charAt(0));
// 此方法得到的是数字字符对应的ASCII码,在这里字符'2'对应的是50
7.5 ASCII码
什么是ASCII码
https://baijiahao.baidu.com/s?id=1726355332105458221&wfr=spider&for=pc
unicode和ascii的区别是什么-电子发烧友网
https://m.elecfans.com/article/601592.html
7.5.1 字符和ascii码相互转化
java字符与ASCII码相互转换
https://blog.csdn.net/qq_38689263/article/details/121227624
java中使用Integer.valueOf(char c)方法可以直接获取一个字符的ASCII码
public class ASCII码 {
public static void main(String[] args) {
// TODO Auto-generated method stub
char a='a';
char A='A';
int a_ascii=Integer.valueOf(a);
int A_ascii=Integer.valueOf(A);
System.out.println("a的ASCII码"+a_ascii);
System.out.println("A的ASCII码"+A_ascii);
//方法二 强制类型转换 字符
System.out.println("a的ASCII码"+(int)'a');
}
}
// 字符转ascii码
System.out.println(s.charAt(i)-0);
// ascii码转字符
System.out.println((char)(97));
7.5.2 字符可以进行减法操作(ascii减法)
Integer i4 = s.charAt(0)-'0';
// 此方法可取数字字符串的具体某个数字的值,得到整形的2
7.6 案例1:字节流读取txt文件中的数字
程序:
public class iotxt {
public static void main(String[] args) {
char aChar = '4';
String x = Integer.toHexString(aChar);
System.out.println(x);
readFile();
//System.out.println((char)e4bd);
}
/**
* 读取TXT文件内容
*/
public static void readFile() {
try {
/**
* 为防止文件建立或读取失败,用catch捕捉错误并打印,也可以throw;
* 注意要用close();
* 不关闭文件会导致资源的泄露,读写文件都同理;
*/
FileInputStream Ins = new FileInputStream("E:\\DoIt\\20220728熟悉操作\\a111111.txt");
int i = Ins.read(); // 自动转为了ascii码
int t = 0;
while(i!=-1) {
System.out.println(t+"读取的字节码为:"+i);
i = Ins.read();
t++;
}
Ins.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
第一种情况:
txt文件
输出:
第二种情况:
txt文件
输出结果
为什么出现上面的结果?
34是4的unicode码
stream不是字节流吗?不是每次应该输出1个字节吗?当txt文件里面是“46 4 1a”,这样就是7个字符,每个字符占2个字节,不应该输出14个字节的值吗?
上面的代码
int i = Ins.read();
自动将字符转为了ascii码,这个可以理解,但是对比中国的“中”为什么占用了3个ascii吗?
7.7 案例2:读取txt文件存的16进制数转为byte数组(16进制的字符串转为10进制)
txt里存的是2个字符表示的16进制数,比如“6a 72”,6a是106的16进制表示。
public class rendtxt {
public static void main(String[] args) {
String path = "E:\\DoIt\\20220728熟悉操作\\0f1f.txt";
//readtxtChar(path);
String ss;
ss = readtxtLine(path);
System.out.println(ss);
byte[] dataM = stringToByte(ss);
}
public static void readtxtChar(String path) {
FileReader reader = null;
try {
reader = new FileReader(path);
//读取字符数据
System.out.println((char) reader.read());
int tmp = 0;
while ((tmp = reader.read()) != -1) {
System.out.println((char) tmp);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
//关闭流对象
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static String readtxtLine(String path) {
// 以行的方式读取,返回字符串
File file = new File(path);
String content = "";
if(file.isFile() && file.exists()){
try {
FileInputStream in = new FileInputStream(file);
InputStreamReader reader = new InputStreamReader(in);
BufferedReader br = new BufferedReader(reader);
String line = null;
while ((line = br.readLine()) != null){
content +=line;
//System.out.println(line);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}catch (IOException e) {
e.printStackTrace();
}
}
return content;
}
public static byte[] stringToByte(String content){
// 16进制表示的字符串转为byte数组
String[] arrString = content.split("\\s+");
byte[] dataMessage = new byte[arrString.length];
for(int i=0; i<5; i++){
dataMessage[i] = new BigInteger(arrString[i], 16).byteValue();
System.out.println("字符数组:"+arrString[i]);
System.out.println("byte数组:"+re);
}
return dataMessage;
}
}
8 转换流InputFileReader和OutFileWriter(字符和字节之间的转换,指定格式进行读写)
看黑马教程,5分钟理解
可以用来解决乱码问题,对应3.8节,但是现在不用了,因为从jdk11开始字符流已经解决这个问题了
记事本可以默认自动将utf-8编码变成GBK,当然你也可以就指定创建utf-8编码
9 对象操作流(读写到本地文件都是直接是字节,不让它转换)
(93条消息) JavaIO流之对象操作流_面向鸿蒙编程的博客-CSDN博客_对象操作流
https://blog.csdn.net/weixin_43715214/article/details/122765112
(93条消息) Java 之 对象操作流_悠然予夏的博客-CSDN博客_对象操作流
https://blog.csdn.net/weixin_52851967/article/details/122041345
10 Properties(字节流或字符流读写map)
1个小案例
本地文件存储的键值对,可以直接用properties进行读取为map
11 java的输入和输出
Java格式化输出(包括对printf,print,println,format等的介绍)
https://blog.csdn.net/han_tiao_tiao/article/details/124219102
12 知识点大总结
(1)字节流输入输出会默认1个字节的数转为utf-8表示的字符;,将英文字符和汉字转为utf8编码的byte数组。1个byte就是8bit的01数,直接读取不进行解码就是1个0-255的整数。
字节流默认不进行编码和解码,直接字节数组进行读和写,编码需要用getbytes方法进行,解码用char或对象数组进行,或者用转换流。
(2)字符流是字节流+编码或解码,每次读取1个或3个字节(英文字符1个byte,中文3个),然后再转为对应的utf-8表示的字符;中文不会出现乱码。自动就进行了编码或者解码。
(3)现在想让它显示的时候也是字节,那么用对象操作流
(4)记住文件底层都是以字节存储的了,txt显示出来不是字节,是因为它这个软件默认把底层的字节转为了GBK编码显示,这样底层的01存储的8bit的字节数组就转为GBK编码的英文字符和汉字了
(5)txt默认是GBK存储的,你也可以另存为选择UTF-8存储。
(6)txt软件的作用就是字节数组进行解码显示。任何文件底层都是字节存储的。