IO就是Input和Output的简写头字母,也就是输入和输出的意思
流就是读写数据时像流水一样从一端流到另外一端,因此得名为"流"
也可以理解为数据从硬盘与程序之间交互的这个过程
文件我们都不陌生,在日常生活中使用的word文件,excel文件,pdf文件等等…都是文件
简单的说 “文件”就是保存数据的地方。
文件在程序中是以流的形式来操作的
流:数据在数据源(文件)和程序(内存)之间经历的途径
输入流:数据从数据源(文件)到程序(内存)的路径
输出流:数据从程序(内存)到数据源(文件)的路径
抽象点形式就是,例如,一个java程序要从C盘的某个文件夹中读取某个文件的数据。这个就是输入流
如果是一个java程序要创建一个文件,且在这个文件中写数据。然后将这个文件保存在C盘中,这个就是输出流
在java中可以使用一个类来在硬盘中创建文件,也就是输出流。
下面用File类来创建一个文件。
File类有三种构造器来创建文件的方法
第一种:
new File(String pathname)//根据路劲构建一个File对象
第二种:
new File(File parent,String child)//根据父目录文件+子路径构建
第三种
new File(String parent,String child)//根据父目录+子路径构建
public class test1 {
public static void main(String[] args) {
//第一种 new File(String pathname)//根据路劲构建一个File对象
String filePath = "D:\\test/news1.txt";//路劲和文件名以文件后缀
File file = new File(filePath);//在程序内存中创建一个file对象
try {
file.createNewFile();//将文件写入硬盘中
System.out.println("创建成功");
} catch (IOException e) {
e.printStackTrace();
}
//第二种 new File(File parent,String child)//根据父目录文件+子路径构建
File parentFile = new File("D:\\");//定义父类目录文件
String fileName = "test/news2.txt";//定义子路劲,以及创建的文件名和后缀
File file2 = new File(parentFile, fileName);//在内存中创建file对象
try {
file2.createNewFile();//将文件写入硬盘中
System.out.println("创建成功");
} catch (IOException e) {
e.printStackTrace();
}
//第三种 new File(String parent,String child)//根据父目录+子路径构建
String parentFile1 = "D:\\";//定义父类目录文件
String childFile = "test/news3.txt";//定义子路劲,以及创建的文件名和后缀
File file3 = new File(parentFile1, childFile);//在内存中创建file对象
try {
file3.createNewFile();//将文件写入硬盘中
System.out.println("创建成功");
} catch (IOException e) {
e.printStackTrace();
}
}
}
File有很多方法,包括对文件的操作,信息读取等等…
获取文件的名字:getName()
获取文件的绝对路径:getAbsolutePath()
获取文件的父类目录:getParent()
返回文件的大小(字节:file.length()
文件是否存在:exists()
是不是一个文件:isFile()
是不是一个目录:isDirectory()
public class test2 {
public static void main(String[] args) {
File file = new File("D:\\test/news1.txt");
System.out.println("获取文件的名字"+file.getName());
System.out.println("获取文件的绝对路劲"+file.getAbsolutePath());
System.out.println("获取文件的父类目录"+file.getParent());
System.out.println("返回文件的大小(字节)"+file.length());
System.out.println("文件是否存在"+file.exists());
System.out.println("是不是一个文件"+file.isFile());
System.out.println("是不是一个目录"+file.isDirectory());
}
}
运行结果:
获取文件的名字news1.txt
获取文件的绝对路径D:\test\news1.txt
获取文件的父类目录D:\test
返回文件的大小(字节)5
文件是否存在true
是不是一个文件true
是不是一个目录false
目录也就是文件夹,在编程中其实目录也可以看做是一个文件。下面有几种方法可以对目录进行创建和删除
mkdir:创建一级目录
mkdirs:创建多级目录
delete:删除空目录或文件
小练习
public static void main(String[] args) {
File file = new File("D:\\test/news1.txt");
if (file.exists()){
file.delete();
}else{
System.out.println("文件不存在");
}
}
public static void main(String[] args) {
File file = new File("D:\\demo2");
if (file.exists()){
file.delete();
}else{
System.out.println("文件不存在");
}
}
public static void main(String[] args) {
File file = new File("D:\\demo2\\a\\b");
if (file.exists()){
System.out.println("存在");
}else{
System.out.println("不存在,正在创建");
file.mkdirs();
}
}
IO就是Input和Output的缩写
IO技术是非常实用的技术,用于处理数据间的传输,如读/写,网络通讯等等
java程序中对于数据的输入和输出操作是以“流(stream)”的方式进行的
java.io包下提供了各种“流”类和接口,用以获取不同种类的数据,并通过方法输入或输出
input输入:读取外部数据(磁盘,光盘等存储设备的数据)到程序中
output:将程序的数据输出到磁盘光盘这些设备中
流:程序使用相同的方式来访问不同的输入/输出源。stream(流)是从起源(source)到接收的(sink)的有序数据
通俗的说:例如 一个人在家网购,商品从商家 到 网购人的手中,这个过程有物流公司来实现。那么这个物流公司就可以看做是一个流,快递小哥也可以看做是流。
字节流可以处理一切,字符流只能处理纯文本。
java中提供了很多流的类用于操作不同类似的文件
抽象基类 | 字节流 | 字符流 |
---|---|---|
输入流 | inputStream | Reader |
输出流 | outputStream | Writer |
java的IO流共涉及40多个类,但是其实都是从4个抽象基类派生的 | ||
由上面4个抽象类派生的子类名称都是以其父类名作为子类名后缀的 |
inputStream抽象类是字节输入流基类,用于从外部读取文件,并对文件进行操作
FileInputStream是inputStream的子类,是一个文件输入流。
可以理解为,物流公司的快递小哥,负责拿到你的包裹为你处理派送等任务。
类图
构造方法
常用方法
close():关闭文件输入流,且释放与此流有关的所有系统资源
read():从该输入流中读取一个字节,如果到达文件末尾返回-1
read(byte[] b):从该输入流中读取b.length个字节存到b数组中,如果到达文件末尾返回-1
read(byte[] b,int off,int len):从该输入流中off处,读取最多len个字节,存入b数组中,如果到达文件末尾返回-1
小练习
要求从D盘中读取test目录下的hello.txt文件(文件里内容是:hello,world),并在控制台输出。
记得关闭流,防止资源浪费。如果不关闭,该流会一直指向该文件资源
使用read(),read(byte[] b),read(byte[] b,int off,int len),三种方法分别实现。
思路分析:
首先创建一个FileInputStream,对象,并让该对象指向hello.txt
然后使用read读取文件,存入程序中的某个属性。
因为一次读取的是一个字节,所以需要遍历读取
代码
第一种:read()
public void readHello1(){
//1.创建一个File对象,hello.txt的路径放进去
File file = new File("D:\\test/hello.txt");
FileInputStream fI = null;
try {
//2.创建一个FileInputStream输入流对象,将路劲给到流,编译异常处理一下
fI = new FileInputStream(file);
//3.创建循环,使用read方法读取字节,因为读取回来的是数字,所以先用int接受,输出强转成char。
int date;
while ((date = fI.read())!= -1){//这里表示先把read返回的值给date,然后判断date是不是-1,如果是-1就表示
System.out.print((char)date);
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
fI.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
运行结果:
hello,world
第二种:read(byte[] b)
public void readHello2(){
//1.创建一个File对象,hello.txt的路径放进去
File file = new File("D:\\test/hello.txt");
FileInputStream fI = null;
try {
//2.创建一个FileInputStream输入流对象,将路劲给到流,编译异常处理一下
fI = new FileInputStream(file);
//3.创建循环,使用read(byte[] b)方法读取字节,存入b数组
byte [] b = new byte[20];
int readlen = 0;
while ((readlen = fI.read(b))!= -1){//这里表示先把read返回的值给date,然后判断date是不是-1,如果是-1就表示
System.out.print(new String(b,0,readlen));//从b数组 0 下标处读取readlen个元素拼接成一个String
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
fI.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
运行结果:
hello,world
第三种
read(byte[] b,int off,int len)
//第三种:read(byte[] b,int off,int len)
@Test
public void readHello3(){
//1.创建一个File对象,hello.txt的路径放进去
File file = new File("D:\\test/hello.txt");
FileInputStream fI = null;
try {
//2.创建一个FileInputStream输入流对象,将路劲给到流,编译异常处理一下
fI = new FileInputStream(file);
//3.创建循环,使用read(byte[] b,int off,int len)方法读取字节,存入b数组,从文件的0处开始读取,到len处。
byte [] b = new byte[20];
int readlen = 0;
while ((readlen = fI.read(b,0,11))!= -1){//这里表示先把read返回的值给date,然后判断date是不是-1,如果是-1就表示
System.out.print(new String(b,0,readlen));//从b数组 0 下标处读取readlen个元素拼接成一个String
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
fI.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
运行结果:
hello,world
outputStream抽象类是字节输出流基类,用于将程序的数据写出到外部存储容器中。
FileOutputStream类是outputStream的子类,是一个文件输出流
构造器
FileOutputStream(File file):创建一个向指定File对象表示的文件写入数据的文件输出流
FileOutputStream(File file,boolean append):创建一个向指定File对象表示的文件写入数据的文件输出流,(在文件内容后面追加内容)
FileOutputStream(String name):创建一个具有指定name的文件,写入数据的文件输出流
FileOutputStream(String name,boolean append):创建一个具有指定name的文件,写入数据的文件输出流,(在文件内容后面追加内容)
常用方法
close:关闭流
write (int b):将指定字节写入文件输出流
write (byte[] b):将b.length个 字节写入文件输出流
write (byte[] b,int off ,int len ):将b.length个 字节写入文件输出流,从b的off处开始,len处结束
小练习
一:
使用FileOutputStream类,在D盘的txt文件夹中创建a.txt,且添加内容为:hello。
public void m1(){
//1.创建FileOutputStream类,并放入 路径和文件名以及类型
String fileName = "D:\\test/a.txt";
FileOutputStream fileOutputStream = null;
try {
fileOutputStream = new FileOutputStream(fileName);
//2.创建文件且写入内容,注意如果发现路径没有该文件,则该方法会自动创建
//此方法只能写入一个字节,fileOutputStream.write('H');
String s = "heelo";
//此方法可以写入一个byte数组,s.getBytes可以将字符串拆分成数组
fileOutputStream.write(s.getBytes());
//此方法表示写入该数组的从0号下标位置写数组.length个
fileOutputStream.write(s.getBytes(),0,s.getBytes().length);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fileOutputStream.close();//关闭流
} catch (IOException e) {
e.printStackTrace();
}
}
}
二:使用FileInputStream和FileoutputStream配合实现拷贝图片或者音乐
思路:
所有的文件都是二进制的,所以可以创建一个输入流一个输出流,输入流获取原文件,然后再给输出流,输出流负责输出到外部硬盘的指定位置。
注意点:注意文件过大的情况,write方法使用write (byte[] b,int off ,int len )的形式防止文件过大没有读取完整
public void copyFile(){
//1.定义原文件的路径和要拷贝到哪里的路径,同时创建输入和输出流
String src = "C:\\4.jpg";
String dest = "D:\\test/1.jpg";
FileInputStream input = null;
FileOutputStream output = null;
//2. 定义一个数组保存文件的二进制编码。然后使用循环给输出流
byte[] b = new byte[1024];
int len = 0;
try {
input = new FileInputStream(src);
output = new FileOutputStream(dest);
while ((len = input.read(b))!= -1){
output.write(b,0,len);
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
input.close();
output.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
FileReader类和FileWriter类都是字符流
FileReader类是字符输入流
FileWriter类是字符输出流
文件字符输入流
构造方法
new FileReader(File /String),使用file对象或string对象创建一个输入流
常用方法
read:每次读单个字符,且返回该字符,如果到达文件末尾则返回-1
read(char[]):批量读取多个字符到数组中,返回读取到的字符数,如果到达文件末尾返回-1
相关API
new String(char[]),将一个char数组 ,转换成string
new String(char[],off,len),将char数组的off到len处转换成string
小练习
使用FileRead从story.txt读取内容,并输出打印在控制台
public class FileReader_ {
@Test
public void m1(){
String fileName = "D:\\test/story.txt";
FileReader Fr = null;
try {
int i = 0;
Fr = new FileReader(fileName);
while ((i = Fr.read()) != -1){
System.out.print((char) i);
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
Fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
文件字符输出流
构造方法
new FileWriter(File /String),使用file对象或string对象创建一个输出流(覆盖模式)
new FileWriter(File /String,true),使用file对象或string对象创建一个输出流,表示在文件末尾追加,而不是覆盖(追加模式)
常用方法
writer(int):写入单个字符
writer(char[]):写入指定数组
writer(char[],off,len):写入指定数组的指定部分
writer(String):写入整个字符串
writer(String,off,len):写入整个字符串的指定部分
相关API
String.toCharArray:将string转换成char[]
注意点
FileWriter使用后必须close或者flush,否则写入不到指定的文件
小练习
使用FileWriter将“风雨之后,定见彩虹”,写入到story.txt文件中(覆盖)
public class FileWriter_ {
@Test
public void m2(){
String fileName = "D:\\test/story.txt";
FileWriter Fw = null;
try {
Fw = new FileWriter(fileName);
Fw.write("风雨之后,定见彩虹");
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
Fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
节点流可以从一个指定的数据源读/写数据,例如FileReader,FileWriter
节点流只能对单个的数据源进行操作。
节点流不仅有对文件操作的流,还有对数据操作的流,对管道操作的流,等等
处理流也叫包装流,是“连接”在已存在的流(节点流或处理流)之上。为程序提供更为强大的读写功能。
处理流类在源码中都会维护一个流的基类,例如BufferedReader,里面就维护了一个Reader的属性。BufferedWriter,里面就维护了一个Writer的属性。这样就可以放入它们的子类到处理六中,使之更加的灵活,功能更加的强大
处理流可以抽象的理解为,包裹电线的一层绝缘胶。
现实生活中,让电流正常运输的其实还是里面的导体(节点流),而外面的绝缘胶可以防止漏电,导体破损等功能(处理流)
而在java中,实际干活的是节点流,处理流虽然包裹节点流,但是处理流并不是干活的,他只是为节点流提供服务的。如图所示
处理流的好处
1.性能的提高:主要以增加缓冲的方式来提高输入输出的效率
2.操作的便捷性:处理流可能提供了一系列便捷的方法来一次输出输出大批量的数据,使用更加灵活方便
下面使用简单的代码来模拟一下修饰器设计模式
public abstract class Reader_ {//基类流
public void FileReader(){}
public void StringReader(){}
}
class FileReader_ extends Reader_{//节点流
@Override
public void FileReader() {
System.out.println("读取了1次文件");
}
}
class StringReader_ extends Reader_{//节点流
@Override
public void StringReader() {
System.out.println("读取了1次字符");
}
}
class BufferedReader_ extends Reader_{//处理流
Reader_ reader_ ;//维护了一个基类属性
public BufferedReader_(Reader_ reader_) {
this.reader_ = reader_;
}
public void FileReaders(int nums) {//在原本的读取上进行扩展,可以读多次
for (int i = 0; i < nums; i++) {
reader_.FileReader();
}
}
public void StringReaders(int nums) {//在原本的读取上进行扩展,可以读多次
for (int i = 0; i < nums; i++) {
reader_.StringReader();
}
}
}
class test{
public static void main(String[] args) {
FileReader_ fileReader_ = new FileReader_();
StringReader_ stringReader_ = new StringReader_();
BufferedReader_ bufferedReader_ = new BufferedReader_(fileReader_);
bufferedReader_.FileReaders(4);
}
}
在诸多处理流中,有一个非常重要,那就是缓冲流。
我们知道,程序与磁盘的交互相对于内存运算是比较慢的,拖累程序的性能。普通流每次读写一个字节就会向磁盘交互一次,那么减少程序与磁盘的交互,就是提升程序效率一种有效手段。缓冲流,就应用这种思路:缓冲流会在内存中设置一个缓存区,缓冲区先存储足够的待操作数据后,再与内存或磁盘进行交互。这样总体交互的数据量是没有变化的,但是交互的次数减少了,每次交互的数量变多了
BufferedReader和BufferedWriter是处理流的缓冲流同时也是字符流,所以它们只能负责处理纯文本。不可以处理二进制文件[音频,视频,图片…]
在上面有了解到流在使用完后需要关闭,但是在处理流中实际工作的还是节点流,按照逻辑上来说只需要关闭被处理流包裹的节点流即可。
但是在java中设计了处理流去关闭节点流的形式,所以在使用完处理流后,使用外层流也就是处理流的close方法就可以了,处理流的方法会去关闭节点流的,就不用我们手动去关闭了。
演示使用
使用BufferedReader读取一个纯文本文件,输出在控制台
public class TT1 {
public static void main(String [] args)throws Exception{
String fileName = "D:\\JavaYu\\cheek1/BitOperator.java";
BufferedReader bufferedReader = new BufferedReader(new FileReader(fileName));
String line = "null";
while ((line = bufferedReader.readLine())!= null){
System.out.println(line);
}
bufferedReader.close();//
}
}
演示使用
使用BufferedWriter在一个一个纯文本文件里写入“hello,world”
public class TT1 {
public static void main(String[] args) throws Exception {
String fileName = "D:\\A.txt";
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(fileName));
bufferedWriter.write("hello,world");
bufferedWriter.newLine();//换行
bufferedWriter.write("hello,world2");
bufferedWriter.close();
}
}
演示使用
使用BufferedReader和BufferedWriter完成对一个文本文件的拷贝。
public class TT1 {
public static void main(String[] args) throws Exception {
String srcFileName = "D:\\A.txt";
String detFileName = "D:\\A2.txt";
BufferedReader br = new BufferedReader(new FileReader(srcFileName));
BufferedWriter bf = new BufferedWriter(new FileWriter(detFileName));
String line ;
while ((line = br.readLine())!= null){
bf.write(line);
bf.newLine();
}
br.close();
bf.close();
}
BufferedInputStream和BufferedOutputStream也是处理流的缓冲流,同时他们也是字节流,用于处理二进制文件
与其他处理流一样,BufferedInputStream和BufferedOutputStream也都各自维护了一个基类的属性,便于处理流操作
BufferedInputStream维护是inputStream
BufferedOutputStream维护的是OutputStream
练习:
要求使用BufferedInputStream和BufferedOutputStream完成对一个图片/视频/音频的拷贝
public static void main(String[] args) {
//定义拷贝源路径和目的路径
String dirFile = "D:\\gugedown/周杰伦 - 我不配.mp3";
String srcFile = "D:\\gugedown/1.mp3";
//定义输入流和输出流
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
//实例化
try {
bis = new BufferedInputStream(new FileInputStream(dirFile));
bos = new BufferedOutputStream(new FileOutputStream(srcFile));
//定义一个char数组。一次读取1024个字节
byte [] b = new byte[1024];
int len= 0;
while ((len = bis.read(b))!= -1){
bos.write(b,0,len);
}
System.out.println("拷贝成功");
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
bis.close();
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
ObjectInputStream和ObjectOutputStream也是处理流,用于处理对象的。
他们提供了对基本类型或对象类型的序列化和反序列化的方法
先看需求:
1.要求将 int a = 100,存储到文件中。要求不仅是存储值,也要存储数据类型。同时可以恢复到程序中
2.要求将Dog dog = new Dog(“小黄”,3)这个对象存储到文件中,且能够恢复
上面的要求就是要求能够将基本数据类型或者对象 进行 序列化和反序列化,也叫串行化
什么是序列化和反序列化
ObjectInputStream: 提供了反序列化功能,因为是输入流
ObjectOutputStream:提供红了序列化功能,因为是输出流
了解完后我们先用ObjectInputStream来试着将数据使用序列化的方式保存到文件中
public class ObjectInputStream_ {
public static void main(String[] args)throws IOException {
String fileName = "D:\\at.txt";//序列化的文件后缀无所谓
//定义一个可序列化的输出流
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(fileName));
//存点已经实现Serializable接口的基本数据
oos.write(100);//会自动转成包装类Integer
//注意序列化的基本数据不一样调用的方法也不一样
oos.writeUTF("11");
oos.writeDouble(1.23);
//存一个可序列化的对象
oos.writeObject(new Dog("小黄",3));
}
}
class Dog implements Serializable {
String name;
int age;
public Dog(String name, int age) {
this.name = name;
this.age = age;
}
}
使用txt文件打开发现是乱码,这是正常的,因为已经不是只存值了,而是连同数据类型一起存了
然后我们再使用ObjectOutputStream读取刚才保存的数据
public void ObjectInputStream_() throws IOException, ClassNotFoundException {
String fileName = "D:\\at.txt";//序列化的文件后缀无所谓
//定义一个输入流
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(fileName));
//读取数据,注意读取需要和保存的顺序一致
System.out.println(ois.readInt());
System.out.println(ois.readUTF());
System.out.println(ois.readDouble());
Object o = ois.readObject();
System.out.println(o);
//关闭流
ois.close();
}
运行结果:
100
11
1.23
Dog{name=‘小黄’, age=3}
在之前的学习中有用到 System.in和System.out这两个属性
System.in 标准输入 编译类型是inputStream 运行类型 BufferedInputStream默认设备:键盘
System.out 标准输出 编译/运行类型都是 PrintStream 默认设备:显示屏
in和out都是System类中维护的静态属性。
常见用法:
Scanner sc = new Scanner(System.in),传给扫描器,接受键盘输入
System.out.println(“sss”);打印某些内容在显示器上
InputStreamReader和OutputStreamWriter都是字符流,他们有一个功能就是可以将字节流转换成字符流
为什么需要进行转换呢?
首先需要了解一下,字节 有很多编码方式例如 UTF-8 ANSI GBK… 而字符流就没有那么多的编码方式
这就造成一个现象就是字节流可以指定编码方式,字符流不可以指定编码方式。
现在有这么一个例子,一个txt文件里面有“你好sdsdsd”这几个字符,是以UTF-8的编码存储的。
我们用BufferedReader字符流去读取它,显示没有问题。
但是我们改一下文件的编码方式为国标ANSI,再去读取就会发现变成了乱码。
UTF-8
ANSI
这里就引发了一个问题,编码不同会导致乱码。而解决方式就是先用字节流指定编码方式,然后再转换成字符流。
使用InputStreamReader解决上面的乱码问题
首先先看一下InputStreamReader的构造器
可以看到InputStreamReader支持将字节流的基类放入,且指定编码。
由此进行一个包装(转换)
练习
将字节流FileInputStream包装(装换成)字符流InputStreamReader对文件进行读取(按照utf-8/gbk格式),再使用BufferedReader读取文本
思路:先将路径放入FileInputStream,然后再将FileInputStream放入InputStreamReader同时指定编码。再将InputStreamReader放入BufferedReader进行读取
public static void main(String[] args) throws IOException {
String fileName = "D://a.txt";
BufferedReader bf = new BufferedReader(new InputStreamReader(new FileInputStream(fileName),"gbk"));
String s = bf.readLine();
System.out.println(s);
bf.close();
}
既然上面有可以读取不同编码的操作,那么OutputStreamWriter自然也可以将不同编码的文本写出到文件中。
下面就使用OutputStreamWriter来写utf-8和gbk两种编码方式的文本到文件中。
首先还是看一下构造器
同样的OutputStreamWriter也可以包装字节输出流的基类同时指定编码
练习
将字节流FileOutputStream包装成(装换成)字符流OutputStreamWriter对文件进行写入(gbk和utf-8)
public static void main(String[] args) throws IOException {
String fileName = "d:\\b.txt";
FileOutputStream fo = new FileOutputStream(fileName);
OutputStreamWriter osw = new OutputStreamWriter(fo, "utf8");
osw.write("你好,世界");
osw.close();
}
PrintStream 字节打印流
PrintWriter 字符打印流
打印流只有输出流没有输入流,一般用于将内容输出到指定的地方,例如控制台,文件中…
PrintStream是字节打印流
可以通过构造方法看出,可以将内容输出到很多地方,而且还可以指定编码
演示使用PrintStream将内容输出到控制台和文件中
public static void main(String[] args) throws IOException {
PrintStream out = System.out;
//打印到控制台
out.print("你好!!!!");
out.close();
//打印到文件中
String fileName = "d:\\c.txt";
System.setOut(new PrintStream(fileName));
System.out.println("你好你好你好");
}
PrintWriter是字符打印流
它同样可以打印内容到不同的地方
演示
public static void main(String[] args) throws IOException {
//打印到控制台
PrintWriter printWriter = new PrintWriter(System.out);
printWriter.print("didiid");
printWriter.close();
//打印到文件
PrintWriter printWriter1 = new PrintWriter("d:\\c.txt");
printWriter1.print("hahhah");
printWriter1.close();
}
在实际开发中可能会用到很多的配置文件,例如需要获取配置文件中的IP,user,pwd。
使用传统方法读取数据是这样的。
public static void main(String[] args) throws IOException {
String fileName = "src\\properties";
BufferedReader bf = new BufferedReader(new FileReader(fileName));
String len = " ";
while ((len = bf.readLine())!= null){
System.out.println(len);
}
}
但是这样的话比较麻烦,如果要改动的什么的就需要去改动源码,不灵活
Properties是一个专门用于读取配置文件的集合类
配置文件的格式:
键 = 值
键 = 值
注意键值对不需要空格,也不用双引号包裹,默认是String类型
Properties的常用方法
load:加载配置文件的键值对到Properties对象
list:将数据显示到指定设备
getProperty(key):根据键获取值
setProperty(key,value):根据键修改值,如果没有键就添加。
store:将Properties对象中的键值对存储到配置文件中,如果含有中文则以unicode码存储
演示使用Properties类对配置文件进行读取和修改
public static void main(String[] args) throws IOException {
String fileName = "src\\properties";
Properties properties = new Properties();
//先将配置文件加载到Properties对象中
properties.load(new FileReader(fileName));
//读取全部配置文件的数据
properties.list(System.out);
//根据键查找值
System.out.println("IP是"+properties.getProperty("ip"));
//根据键修改值
properties.setProperty("pwd","999");
System.out.println(properties.getProperty("pwd"));
}
演示使用Properties类将配置数据保存到新的配置文件
public void test7() throws IOException{
String fileName = "src\\properties2";
Properties properties = new Properties();
properties.setProperty("charset","gbk");
properties.setProperty("user","嗡嗡嗡");
properties.setProperty("pwd","9090");
properties.store(new FileWriter(fileName),"这里可以写注释");
}
一:编程题
1)判断D盘下有没有文件夹mytemp,如果没有就创建
2)在D:\mytemp目录下,创建文件hello.txt
3)如果hello.txt已经存在。提示该文件存在,就不要重复创建了
4) 并且在hello.txt写入hello.world
public static void main(String[] args) throws IOException {
//定义文件夹的路径
String filePath = "d:\\mytemp";
//创建File对象,判断该文件是否存在
File file = new File(filePath);
if (!file.exists()){
//如果不存在就创建
if (file.mkdirs()){
//创建成功就提示创建成功
System.out.println("创建文件夹成功");
}else{
System.out.println("创建失败");
}
}else{
//如果存在就提示不需要创建
System.out.println("已经存在不需要创建");
}
//定义hello.txt的路径
String fileName = "D:\\mytemp/hello.txt";
//判断该文件是否已经存在
File file1 = new File(fileName);
if(file1.exists()){
//如果存在就提示已经存在
System.out.println("hello.txt,已存在不需要创建");
}else{
//如果不存在就创建且写入内容
file1.createNewFile();
//创建输出流写出
FileWriter fileWriter = new FileWriter(file1);
fileWriter.write("hello.word1");
fileWriter.close();
}
}
二:编程题
使用BufferedReader读取一个文本文件,为每行加上行号,连同内容一起输出在屏幕上
public static void main(String[] args) throws IOException {
String fileName = "d:\\mytemp/hello.txt";
BufferedReader bf = new BufferedReader(new FileReader(fileName));
String len = null;
int num = 0;
while ((len = bf.readLine())!= null){
System.out.println(++num +len);
}
bf.close();
}
如果改变了文本的编码,就需要用到转换流。
public class test2 {
public static void main(String[] args) throws IOException {
String fileName = "d:\\mytemp/hello.txt";
FileInputStream fr = new FileInputStream(fileName);
InputStreamReader isr = new InputStreamReader(fr,"gbk");
BufferedReader bf = new BufferedReader(isr);
String len = null;
int num = 0;
while ((len = bf.readLine())!=null){
System.out.println(++num + len);
}
bf.close();
fr.close();
}
}
三:编程题
1编写一个dog.properties配置文件
name=tom
age=5
color=red
2编写Dog类(name,age,color)创建一个dog对象,读取dog配置文件用相应的内容完成初始化,并输出
3创建完成后将改对象序列化保存到d:\mytemp文件中,然后反序列化读取输出
public class test3 {
public static void main(String[] args) throws IOException, ClassCastException, ClassNotFoundException {
String fileName = "src\\dog";
Properties p = new Properties();
p.setProperty("name","tom");
p.setProperty("age","5");
p.setProperty("color","red");
p.store(new FileWriter(fileName),null);
Dog dog = null;
String name1 = p.getProperty("name");
int age1 = Integer.parseInt(p.getProperty("age"));
String color1= p.getProperty("color");
dog = new Dog(name1,age1,color1);
System.out.println(dog);
//序列化
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("d:\\mytemp/dog.date"));
oos.writeObject(dog);
oos.close();
//反序列化
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("d:\\mytemp/dog.date"));
Dog d2 = (Dog) ois.readObject();
System.out.println(d2);
ois.close();
}
}
class Dog implements Serializable {
String name;
int age;
String color;
public Dog(String name, int age, String color) {
this.name = name;
this.age = age;
this.color = color;
}
@Override
public String toString() {
return "Dog{" +
"name='" + name + '\'' +
", age=" + age +
", color='" + color + '\'' +
'}';
}
}