一、转换流
1.1 字符编码和字符集
字符编码:计算机中储存的信息都是用二进制数表示的,而我们在屏幕上看到的数字、英文、标点符号、汉字等字符是二进制
数转换之后的结果。按照某种规则,将字符存储到计算机中,称为编码 。反之,将存储在计算机中的二进制数按照
某种规则解析显示出来,称为解码 。字符编码就是一套自然语言的字符与二进制数之间的对应规则
字符集:编码表,是一个系统支持的所有字符的集合。
常见的字符集:ASCII字符集、GBK字符集、Unicode字符集等
3.2 字符转化流OutputStreamWriter
OutputStreamWriter将字符流转换为字节流。是字符流通向字节流的桥梁, 可使用指定的码表将要写入流中的字符编码成字节。
它使用的字符集可以由名称指定或者给定,否则则按平台的默认字符集
构造方法
//构造一个默认编码集的OutputStreamWriter类
OutputStreamWriter osw = new OutputStreamWriter(OutputStream out);
//构造一个指定编码集的OutputStreamWriter类。
OutputStreamWriter osw = new OutputStreamWriter(OutputStream out,String charsetName);
代码演示
public class OutPutStreamWriter {
public static void main(String[] args) throws IOException {
write_utf_8();
write_gbk();
}
/*
使用转换流OutputStreamWriter 写UTF-8格式的文件
*/
private static void write_gbk() throws IOException {
//指定编码集,写GBK格式的文件
OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream("gbk.txt"),"GBK");
osw.write("你好");
osw.flush();
osw.close();
}
/*
使用转换流OutputStreamWriter 写UTF-8格式的文件
*/
private static void write_utf_8() throws IOException {
//不指定编码集 默认使用utf-8
OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream("utf-8.txt"));
osw.write("你好");
osw.flush();
osw.close();
}
}
字符写入的时候,是将数据写入到内存缓冲区中(字符转换为字节),写入完成需要使用flush方法,把内存缓冲区的数据,刷新到文件中。
close方法会关闭资源前会将内存缓冲区的数据刷新到文件中。
同样想达到追加写入的文件时,只需在构造方法中传入的FileOutputStream类的一个对象,该类的构造方法增加一个参数true,打开追加写开关
//实现追加写
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("c.txt",true));
构造一个指定编码集的OutputStreamWriter类。
由于使用的是IDEA软件,默认编码集为UTF-8,所有在编码解码上面不存在问题。
指定编码集为GBK时,会出现乱码问题
1.3 转换流InputStreamReader类
InputStreamReader,是Reader的子类,是从字节流到字符流的桥梁。读取字节,并适用指定的字符集将读取的字节进行解码为字符。字符集可以由名称指定,也可以使用默认的字符集
1.3.1 构造方法
InputStreamReader(InputStream in) : 创建一个使用默认字符集的字符流。
InputStreamReader(InputStream in, String charsetName) : 创建一个指定字符集的字符流。 第二个参数参数为编码表名称
使用转换流InputStreamReader读取上面所写入的文件
public class InPutStreamReader {
public static void main(String[] args) throws IOException {
//读取utf-8编码的文件
read_utf_8();
//读取gbk编码的文件 由于IDEA默认使用utf-8,所以在项目目录打开的会是乱码
read_gbk();
}
private static void read_gbk() throws IOException {
InputStreamReader isr=new InputStreamReader(new FileInputStream("gbk.txt"),"gbk");
int len=0;
while ((len=isr.read())!=-1){
System.out.println((char) len);
}
isr.close();
}
private static void read_utf_8() throws IOException {
InputStreamReader isr=new InputStreamReader(new FileInputStream("utf-8.txt"),"utf-8");
int len=0;
while ((len=isr.read())!=-1){
System.out.println((char) len);
}
isr.close();
}
}
二、数据输入输出流
数据输入流:DataInputStream 。允许应用程序以与机器无关方式从底层输入流中读取基本 Java 数据类型
数据输出流:DataOutputStream。允许应用程序以适当方式将基本 Java 数据类型写入输出流中。
特点:可以写基本类型的数据,可以读取基本类型数据
public class DataDemo01 {
public static void main(String[] args) throws IOException {
//数据输出流
DataOutputStream dos = new DataOutputStream(new FileOutputStream("aa.txt"));
dos.writeBoolean(true);//写入布尔值
dos.writeDouble(3.14);//写入Double类型
dos.writeInt(20);//写入int类型
dos.writeUTF("字符串");//写入字符串类型
dos.close();
//数据输入流
DataInputStream dis = new DataInputStream(new FileInputStream("aa.txt"));
System.out.println(dis.readBoolean());//true
System.out.println(dis.readDouble());//3.14
System.out.println(dis.readInt());//20
System.out.println(dis.readUTF());//字符串
dis.close();
}
}
**注意:**数据输出流输入流的读取顺序不能乱。怎么写的就怎么读取
三、内存操作流
3.1 操作字节数组
操作字节数组:ByteArrayOutputStream和ByteArrayInputStream
特点:不直接关联文件,只在内存中操作。底层维护的是一个字节数组
ByteArrayOutputStream
- 此类实现了一个输出流,数据被写入到一个byte数组
- 数组(缓冲区)会随着数据的写入而自动增长
- 可以使用toByteArray方法和toString方法获取数据
- 不用关闭流,因为这个流的方法在关闭之后仍然可以调用,且不会产生任何IOException
ByteArrayInputStream 包含了一个内部缓冲区,该缓冲区包含了从流中读取的字节。同样也是关闭无效。
public class ByteDemo01 {
public static void main(String[] args) throws IOException {
//ByteArrayOutputStream 此流不许关闭
ByteArrayOutputStream bos = new ByteArrayOutputStream();
bos.write("你好".getBytes());
bos.write("同学".getBytes());
bos.write("学习".getBytes());
//通过toByteArray()取出数据
byte[] bytes = bos.toByteArray();
System.out.println(new String(bytes));
//通过toString()取出数据
System.out.println(bos.toString());
/*ByteArrayInputStream( byte[] buf
创建一个 ByteArrayInputStream,使用 buf 作为其缓冲区数组。
*/
ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
//取出数据
int len=0;
byte[] bytes1=new byte[1024];
while ((len=bis.read(bytes1))!=-1){
System.out.println(new String(bytes1,0,len));
}
}
}
3.2 操作字符数组
操作字符数组:CharArrayWrite和CharArrayReader
CharArrayWrite:此类实现一个可用作 Writer 的字符缓冲区。缓冲区会随向流中写入数据而自动增长。
CharArrayReader:此类实现一个可用作字符输入流的字符缓冲区。
可以使用toCharArray方法和toString方法获取数据 底层维护的是一个字符数组
public class CharDemo {
public static void main(String[] args) throws IOException {
CharArrayWriter out = new CharArrayWriter();
out.write("aaaa");
out.write("bbbb");
out.write("cccc");
/*char[] chars = out.toCharArray();
String s = String.valueOf(chars);*/
String string = out.toString();
System.out.println(string);
CharArrayReader charArrayReader = new CharArrayReader(out.toCharArray());
int len=0;
char[] chars=new char[1024];
while ((len=charArrayReader.read(chars))!=-1){
System.out.println(new String(chars,0,len));
}
}
}
3.3 操作字符串
操作字符串:StringWriter和StringReader
StringWriter:一个字符流,可以用其回收在字符串缓冲区中的输出来构造字符串。
StringReader:其源为一个字符串的字符流。
底层使用的是StringBuffer
public class StringDemo {
public static void main(String[] args) throws IOException {
StringWriter stringWriter = new StringWriter();
stringWriter.write("abc");
stringWriter.write("abc");
stringWriter.write("abc");
stringWriter.write("abc");
String string = stringWriter.toString();
System.out.println(string);
StringReader stringReader = new StringReader(string);
int len=0;
char[] chars=new char[1024];
while ((len=stringReader.read(chars))!=-1){
System.out.println(new String(chars,0,len));
}
}
}
3.4 练习:将两首音乐合并为一首
- 利用内存操作流中的操作字节数组
public class mixMusic {
public static void main(String[] args) throws IOException {
//创建两首歌曲的文件字节输入流
FileInputStream fis1 = new FileInputStream("C:\\Users\\asus\\Desktop\\许巍 - 蓝莲花.mp3");
FileInputStream fis2 = new FileInputStream("C:\\Users\\asus\\Desktop\\许巍 - 曾经的你.mp3");
//创建一个ArrayList集合 放入两首歌 读取到内存操作流
ArrayList<FileInputStream> list = new ArrayList<>();
list.add(fis1);
list.add(fis2);
//遍历集合 读取数据。写入到内存操作流
int len=0;
byte[] bytes=new byte[1024];
//创建操作字节数组的内存操作流
ByteArrayOutputStream bos = new ByteArrayOutputStream();
for (FileInputStream fis : list) {
while ((len=fis.read(bytes))!=-1){
bos.write(bytes,0,len);
}
fis.close();
}
//取出两首歌曲的字节数组
byte[] byteArray = bos.toByteArray();
//创建内存操作流读取数据 参数传递整个的字节数组
ByteArrayInputStream bis = new ByteArrayInputStream(byteArray);
//创建文件字节输出流
FileOutputStream fos = new FileOutputStream("C:\\Users\\asus\\Desktop\\许巍歌曲合集.mp3");
int len2=0;
byte[] bytes2=new byte[1024];
while ((len2=bis.read(bytes2))!=-1){
fos.write(bytes2,0,len2);
}
fos.close();
}
}
四、打印流PrintStream
平时我们在控制台内进行打印输出,是调用 print 方法和 println 方法完成的,这两个方法都来自于PrintStream 类,这个类能够方便打印各种数据类型的值,是一种便捷的输出方式。
特点:打印流只关联目的地,不关联源文件。不能读取,只能写入
4.1 字节打印流PrintStream
4.1.2 构造方法
PrintStream(File file) 创建具有指定文件且不带自动行刷新的新打印流。
PrintStream(String fileName) 创建具有指定文件名称且不带自动行刷新的新打印流。
public class PrintStreamDemo01 {
public static void main(String[] args) throws IOException {
//PrintStream(File file) 创建具有指定文件且不带自动行刷新的新打印流。
PrintStream printStream = new PrintStream(new File("a.txt"));
//父类方法
printStream.write("你好".getBytes());
printStream.write("\r\n".getBytes());
printStream.write(97);
/*特有方法 println方法 可以写入任意类型数据 并且换行
print 方法 ,写入任意类型数据,不换行*/
printStream.println("你好");//字符串
printStream.println(true);//布尔值
printStream.print("print方法不换行");
printStream.print(100);
/*同样可以通过其他方法得到PrintStream,这样不一定会往文件中写入
System.out的返回值是一个PrintStream,这样的话,输出流关联的就是控制台打印 */
//out 标准”输出流。此流已打开并准备接受输出数据。通常,此流对应于显示器输出
PrintStream out = System.out;
out.print(50);
out.write("Java".getBytes());
out.println("大家好");
System.out.println("平时采用的是链式编程");
}
}
4.2 字符打印流PrintWriter
4.2.2 构造方法
PrintWriter(File file) 使用指定文件创建不具有自动行刷新的新 PrintWriter。
PrintWriter(String fileName) 创建具有指定文件名称且不带自动行刷新的新 PrintWriter。
PrintWriter(OutputStream out, boolean autoFlush) 通过现有的 OutputStream 创建新的 PrintWriter。
public class PrintWriterDemo01 {
public static void main(String[] args) throws FileNotFoundException {
//PrintWriter(File file) 使用指定文件创建不具有自动行刷新的新 PrintWriter。
PrintWriter printWriter = new PrintWriter(new File("b.txt"));
printWriter.write("你好");
printWriter.write(98);
//字符流必须刷新才能写入到文件中 必须手动刷新
printWriter.flush();
printWriter.close();//关闭流
/*PrintWriter(OutputStream out, boolean autoFlush) 通过现有的 OutputStream 创建新的 PrintWriter。
第二个参数 是选择自动刷新的开关
创建一个能够启动自动刷新,只会在调用println、printf 或 format 方法中的一个方法的时候,会完成自动刷新
*/
PrintWriter printWriter1 = new PrintWriter(new FileOutputStream("bb.txt"));
printWriter1.println("自动刷新");
printWriter1.print("需要手动刷新才能写入文件中");
printWriter1.close();
}
}
4.3 使用打印流复制文本文件
由于打印流只能写入数据,所以需要找寻另一个流(这里使用BufferedReader)配合,实现文本文件的复制。
public class CopyFile {
public static void main(String[] args) throws IOException {
//使用BufferedReader读取文本文件
BufferedReader br = new BufferedReader(new FileReader("mixMusic.java"));
//使用打印流PrintWriter写入文本文件的内容,开启自动刷新
PrintWriter printWriter = new PrintWriter(new FileOutputStream("mixMusicCopy.java"), true);
//读取数据,写入数据
String line=null;
while ((line=br.readLine())!=null){
//写入数据,并且自动刷新
printWriter.println(line);
}
printWriter.close();
br.close();
}
}
五、键盘录入并且写入文件
要求:做到将键盘录入的数据,写入到指定文件中,并且设定一个停止按钮结束键盘的录入
public class ScannerDemo {
public static void main(String[] args) throws IOException {
/* InputStream in = System.in;
Scanner scanner = new Scanner(in);
System.in的返回值是一个输入流,可以结合BufferedReader中的readLine方法
从屏幕读取一行
*/
//这个时候bufferedReader关联的文本文件就是键盘录入 System.in 可以实现键盘录入数据
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
//结合BufferedWriter,将BufferedReader读取键盘录入的数据,写入到BufferedWriter关联的文件中
BufferedWriter bufferedWriter=new BufferedWriter(new FileWriter("PrintDemo.txt"));
while (true){
System.out.println("请输入录入的数据");
String line=null;
while ((line=bufferedReader.readLine())!=null){
//结束条件
if (line.equals("stop")){
bufferedWriter.close();
bufferedReader.close();
break;
}
bufferedWriter.write(line);
bufferedWriter.newLine();
bufferedWriter.flush();
System.out.println("控制台打印"+line);
}
break;
}
}
}
补充:创建Scanner对象时,参数传递一个文件
Scanner(File source) 构造一个新的 Scanner,它生成的值是从指定文件扫描的。
参数为文件类,读取关联文件的数据
public class ScannerDemo02 {
public static void main(String[] args) throws FileNotFoundException {
//使用Scanner关联文件
Scanner scanner = new Scanner(new File("mixMusic.java"));
/* //扫描文件
while (scanner.hasNextLine()){
String line = scanner.nextLine();
System.out.println(line);//控制台打印文件的数据
}*/
//使用Scanner复制文件 开启自动刷新 第一个参数需要是FileOutputStream
PrintWriter pw = new PrintWriter(new FileOutputStream("mixMusic3.java"),true);
while (scanner.hasNextLine()){
pw.println(scanner.nextLine());
pw.flush();
}
//关闭流
pw.close();
scanner.close();
}
}