IOExercise1
package IOExercise20240806;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class IOExercise1 {
public static void main(String[] args) throws IOException {
// IO流(input output) 输入流和输出流————>流向内存是输入流,流出内存是输出流
// Java中的IO操作主要是用java.io包下的内容,进行输入、输出操作;输入叫读取数据、输出叫写出数据
// IO流主要分为输入流和输出流(流向内存是输入流,流出内存是输出流)
// 根据数据的类型也可以分为字节流和字符流
// 字节流:以字节为单位读取数据
// 字符流:以字符为单位读取数据
// 字节流(顶级父类)
// 字节输入流:InputStream 字节输出流:OutputStream
// 计算机的底层存储是以二进制的形式进行的,所以说字节流可以传输任意的文件数据
// 常用子类:FileOutputStream,顾名思义,是文件的输出流,可以将内存中的数据输出到File对象所表示的文件中
// 构造方法
// FileOutputStream(File file) 用指定的File对象创建文件输出流
File file1 = new File("D:\\Exercise\\庄小琳.txt");
FileOutputStream fos1 = new FileOutputStream(file1);
// 这里会产生FileNotFoundException异常,需要throws到方法签名处
// FileOutputStream(String name)
FileOutputStream fos2 = new FileOutputStream("D:\\Exercise\\庄小琳.txt"); // 其中参数是路径和文件名
// 当创建流对象时,必须传入文件路径,如该路径下没有这个文件,那么会创建该文件,如果有这个文件,则会清空这个文件
// 写出字节
// write(int b) 写出一个字节数据到FileOutputStream表示的文件中
fos2.write("hello world".getBytes()); // 产生IOException,需要throws
// 使用完流之后,不再使用了必须使用close方法停止对文件的占用
fos1.close();
fos2.close();
}
}
IOExercise2
package IOExercise20240806;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
public class IOExercise2 {
public static void main(String[] args) throws IOException {
// 字节流write(byte[] b) 每次可以向表示的文件中写出byte数组中的数据
File file1 = new File("D:\\Exercise\\words.txt");
byte[] bytes = {97,98,99,100,101};
FileOutputStream fos1 = new FileOutputStream(file1);
fos1.write(bytes); // 传递byte数组进行写入成功
// 可以通过String中的getBytes方法简洁地将字符串转化为byte数组,从而写入
fos1.write("你好世界".getBytes()); // 可以写中文
// write(byte[] b, int off, int len) 每次写入byte数组中从off索引开始,长度为len的字节数据
fos1.write("hello world".getBytes(), 2, 5); // 写hello world中从2索引开始,长度为5的数据"llo w"
fos1.close(); // close之后再想使用这个流就会报错!close必须再不用流之后写
}
}
IOExercise3
package IOExercise20240806;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
public class IOExercise3 {
public static void main(String[] args) throws IOException {
// 追加数据
// FileOut(in)putStream中每次创建文件输出(入)流都会清空文件中的内容,但是可以通过控制构造方法中的append来追加内容
// FileOutputStream(File file, boolean append) // append默认是false,但是可以传入true表示追加,那么就不会清空文件
File file1 = new File("D:\\Exercise\\words.txt");
FileOutputStream fos1 = new FileOutputStream(file1, true); // 构造方法传入true,表示追加内容
fos1.write("一二三四五六七八九十".getBytes()); // 文件中之前的内容没有被清空,将write的内容追加到了后面
fos1.close();
// FileOutputStream(String name, boolean append)
FileOutputStream fos2 = new FileOutputStream("D:\\Exercise\\words.txt", true);
fos2.write("张三李四王五".getBytes());
fos2.close(); // 成功追加
// 写出换行符
// windows系统中换行符是\r\n,但是Java中只需要写\n或者\r都会在底层自动补充为\r\n,但是建议还是写全
FileOutputStream fos3 = new FileOutputStream(file1);
fos3.write("床前明月光,\r\n疑似地上霜。\n举头望明月,\r低头思故乡。".getBytes());
// 显然\r\n换行成功,但是\r或者\n也可以实现换行,是因为Java中写\n或者\r都会在底层自动补充为\r\n,但是建议写全
fos3.close();
// 补充:
// Windows中每行的结尾是回车+换行 \r\n
// Linux中每行结尾只有换行 \n
// Mac中每行结尾是回车 \r 从Mac OS X开始,与Linux统一
}
}
IOExercise4
package IOExercise20240806;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class IOExercise4 {
public static void main(String[] args) throws IOException {
// 字节输入流
// InputStream 读取字节信息到内存中
// FileInputStream(File file) 通过一个File对象创建FileInputStream,该文件由文件系统中的File对象命名
File file1 = new File("D:\\Exercise\\words.txt");
FileInputStream fis1 = new FileInputStream(file1);
FileInputStream fis2 = new FileInputStream("D:\\Exercise\\words.txt");
// int read() 读取流中的下一个字节提升为int类型并返回,读取到文件末尾之后,返回-1
int b;
while((b = fis1.read()) != -1) {
System.out.print((char)b);
}
fis1.close();
fis2.close();
/* 细节:为什么一定要用一个变量接收read方法的返回值?
read方法有一个指针指向文件的开始,每次调用都是返回对应的值然后后移指针,假如只用fis.read的返回值
和-1比较的话,那么在循环内无法使用返回值对其进行操作,想要操作再次调用read方法,会导致指针再次后移
从而导致一些文件中的数据被跳过了 */
// read(byte[] b) 每次读取byte数组的长度个字节,读取到byte数组中,返回读取到的有效字节的个数,读到末尾返回-1
byte[] bytes = new byte[2]; // 每次可以读2个字节到byte数组中
FileInputStream fis3 = new FileInputStream("D:\\Exercise\\words.txt");
int len; // 定义变量len,代表每次读取的有效个数
while((len = fis3.read(bytes)) != -1) {
System.out.println(new String(bytes));
// 这样输出有bug,假如最后一次读取只读了一个有效数据,但是bytes中原来1索引还有数据,这样输出会导致重复输出
System.out.println(new String(bytes, 0, len));
// 改成这样输出,只会输出到0索引到len(读取的有效个数)索引的数据,避免了最后一次读取的重复输出
}
// 使用数组读取,每次读取多个字节,减少了系统间的IO操作次数(IO操作费时),从而提高了读写的效率,建议开发中使用。
}
}
IOExercise5
package IOExercise20240806;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
public class IOExercise5 {
public static void main(String[] args) throws IOException {
// 字符流
/* 当用字节流读取文本文件时,遇到问题————遇到中文字符时,根据编码规则不同,占用不同的字节数,假如用字节流读取
会导致中文读取不全,从而产生乱码,所以说Java提供字符流类,专门处理文本文件 */
// 字符输入流Reader,字符输出流Writer
// FileReader类 此类是读取字符文件的便利类,构造时使用系统默认的字符编码和默认的字符缓冲区
// 注:1.字符编码:字节和字符的对应规则,Windows中中文默认编码是GBK(中文2字节),idea中是UTF-8(中文3字节)
// 2.字节缓冲区,一个字节数组,用来临时存储字节数据,是先从文件中读取数据到缓冲区中,然后再从缓冲区中读取到内存中
// 创建一个流对象时,必须传入一个正确的文件路径
// FileReader(File file) 用要读取的File对象创建FileReader对象
File file1 = new File("D:\\Exercise\\words.txt");
FileReader fr1 = new FileReader(file1);
// FileReader(String name) 用要读取的文件的文件路径创建FileReader对象
FileReader fr2 = new FileReader("D:\\Exercise\\words.txt");
// read() 每次读取一个字符的数据,提升为int类型,并且返回,读到文件末尾返回-1
int result;
while ((result = fr2.read()) != -1) {
System.out.print((char)result); // 根据字符读取,就可以正确的读取到中文了
}
// 注意:此处的fr2已经读到了文件末尾了,如果在下面的代码再次用fr2阅读文件则不会读到任何东西!!!
// 细节,中文的标点符号就相当于中文字符,也会根据不同的编码规则占用不同的字节
// read(char[] cbuf) 每次读取cbuf数组长度的字符到数组中,返回读取到的有效字符的个数,读取到文件末尾返回-1
int len; // 表示读取到的有效长度
char[] charArray = new char[3];
while ((len = fr1.read(charArray)) != -1) {
System.out.println(new String(charArray, 0, len)); // 改良后的写法,只会输出有效的读取
}
}
}
IOExercise6
package IOExercise20240806;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
public class IOExercise6 {
public static void main(String[] args) throws IOException {
// 字符输出流 write
// void write(int c) 写入单个字符(从内存到文件)
// void write(char[] cbuf) 写入字符数组
// void write(char[] cbuf, int off, int len) 写入字符数组的某一部分,从off索引开始,写入len个元素
// void write(String str) 写入字符串
// void write(String str, int off, int len) 写入字符串的一部分
// void flush() 刷新该流的缓冲区(先是将内存中的数据写入到缓冲区,然后再从缓冲区一起写入文件,可以减少IO操作,提高效率)
// FileWrite类
// FileWrite是以字符的形式写出到文件的便利类,构造方法使用系统默认的字符编码和默认的字节缓冲区
// FileWriter(File file) 用给定需要写入的File对象创建FileWriter对象
File file1 = new File("D:\\Exercise\\words.txt");
FileWriter fw1 = new FileWriter(file1);
// FileWriter(String fileName) 用需要写入的文件路径创建FileWriter对象
FileWriter fw2 = new FileWriter("D:\\Exercise\\words.txt");
// write(int b) 每次写一个字符数据
fw2.write(97);
fw2.write('4'); // 此处有类型提升
fw2.write('c');
fw2.write(30000);
// 注:此时只是将数据成功写入到了缓冲区中,并非直接写入了缓冲区
// write方法完成之后,必须要用close方法或者flush方法,才可以将缓冲区内的数据真正的写入到对应的文件中
// flush和close的区别
// flush:刷新缓冲区,将缓冲区的数据写入到对应的文件中去,流对象仍然可以继续使用!
// close:先刷新缓冲区,然后通知系统释放资源,流对象不可以继续使用!
fw2.close();
// 注意,flush≠close,所以说即使使用了flush,最后不用流了还是需要close
}
}
IOExercise7
package IOExercise20240806;
import java.io.FileWriter;
import java.io.IOException;
public class IOExercise7 {
public static void main(String[] args) throws IOException {
// write(char[] cbuf) 和 write(char[] cbuf, int off, int len)
FileWriter fw = new FileWriter("D:\\Exercise\\words.txt");
fw.write("朝花夕拾".toCharArray());
fw.write("这不好吧".toCharArray(), 0, 2);
fw.write('啊');
// write(String str) 和 write(String str, int off, int len)
fw.write("\n山重水复疑无路,");
fw.write("\n柳暗花明又一村。", 0, 9); // 换行符和标点符号都算数据 个数
fw.close();
// 字符流只能操作文本文件,无法操作图片和视频等非文本文件,所以说单纯读写文本时可以使用字符流,
// 其他情况使用字节流
}
}