——- android培训、java培训、期待与您交流! ———-
IO流的概述
I: Input(输入) , O: Output(输出)
作用: 用于不同设备之间的数据传输
我们经常用的上传下载,都涉及了IO流。
File 类
File 类 : 是文件或者文件夹的抽象表示形式
抽象的表示形式可以理解为当我们通过 new 创建File对象时,事实上并不一定真实存在一个File对象,
构造方法:
public File(String fileName) : 那一个文件或者文件夹路径封装成一个File对象
public File (String parent , String child ) : 通过父文件路径和子文件或者文件夹路径构建一个File对象
public File (File parent , String child ) : 通过父文件和子文件或者文件夹路径构建一个File对象
成员方法:
创建功能相关的方法:
public boolean createNewFile() : 创建一个文件
public boolean mkdir() : 创建一个文件夹,但是只能创建单级文件夹
public boolean mkdirs(): 可以用来创建多级文件夹
File类的删除功能:
public boolean delete():删除文件或者文件夹
File类的重命名功能:
public boolean renameTo(File dest):把文件重命名为指定的文件路径
注意事项:
如果路径名相同,就是改名。
如果路径名不同,就是改名并剪切。
File类的判断功能:
public boolean isDirectory(): 判断是否是目录
public boolean isFile(): 判断是否是文件
public boolean exists(): 判断是否存在
public boolean canRead(): 判断是否可读
public boolean canWrite(): 判断是否可写
public boolean isHidden(): 判断是否隐藏
File类的获取功能:
public String getAbsolutePath(): 获取绝对路径
public String getPath(): 获取相对路径
public String getName(): 获取名称
public long length(): 获取长度。字节数
public long lastModified(): 获取最后一次的修改时间,毫秒值
public String[] list(): 获取指定目录下的所有文件或者文件夹的名称数组
public File[] listFiles(): 获取指定目录下的所有文件或者文件夹的File数组
public String[] list(FilenameFilter filter)
public File[] listFiles(FilenameFilter filter)
下面做一个练习:判断E:\file目录下是否有后缀名为.jpg的文件,如果有,就输出该文件名称
import java.io.File;
/**
* 需求:判断E:\file目录下是否有后缀名为.jpg的文件,如果有,就输出该文件名称
*
* 步骤:
* a: 封装指定的目录为一个File对象
* b: 获取指定路径下所有的文件或者文件夹对应的File数组
* c: 遍历数组,获取每一个元素然后进行判断,判断是否是文件并且当前的元素是以.jpg结尾的
* 如果满足上面的判断添加就直接输出该元素对应的名称
*
*/
public class FileTest {
public static void main(String[] args) {
// 封装指定的目录为一个File对象
File file = new File("E:\\file") ;
// 获取file这个文件路径下所有的文件或者文件夹对应的File数组
File[] files = file.listFiles() ;
// 遍历
for(File f : files ){
// 判断
if(f.isFile() && f.getName().endsWith(".jpg")){
System.out.println(f.getName());
}
}
}
}
File 类还是相对好理解的,方法也不多。练习的多了也就得心应手了
递归:
概述: 就是方法定义中调用方法本身的现象 ;
注意事项:
a: 递归一定要有出口
b: 递归的次数不宜过多
递归体现的思想: 拆分思想和合并思想
第一个练习题: 求5的阶乘
public static int jieCheng(int n) {
if(n == 1 ){
return 1 ;
}else {
return n * jieCheng(n - 1);
}
}
第二个练习题: 不死神兔
public static int getCount(int n){
if(n == 1 || n == 2 ){
return 1 ;
}else {
return getCount(n - 1) + getCount(n -2) ;
}
}
第三个练习题: 输出指定目录下所有的以.java结尾的文件的绝对路径
public static void printFilePathName(File file) {
// 获取指定的路径下所有的文件或者文件夹对应的File数组
File[] files = file.listFiles() ;
// 遍历
for(File f : files) {
// 判断
if(f.isFile()){
if(f.getName().endsWith(".java")){
System.out.println(f.getAbsolutePath()) ;
}
}else {
//递归printFilePathName()方法
printFilePathName(f) ;
}
}
}
第四个练习题: 删除文件夹
public static void deleteFolder(File file){
// 获取指定的路径下所有的文件或者文件夹对应的File数组
File[] files = file.listFiles() ;
// 遍历
for(File f : files) {
// 判断
if(f.isFile()) {
System.out.prinltn(f.getAbsolutePath() + "----" + f.delete()) ;
}else {
//递归deleteFolder()方法
deleteFolder(f) ;
}
}
// 删除文件夹
System.out.println(file.getAbsolutePath() + "---" + file.delete()) ;
}
递归总结:现实开发中能用循环解决的问题尽量不要使用递归解决,因为每次递归调用都会在栈内存中开开辟
一个空间,比较耗内存。
IO流 :
I: 输入
O: 输出
什么是输入和输出: 说这个输入和输出问题是相对于内存而言的.
分类:
a: 按照流向进行划分
输入流
输出流
b: 按照操作数据的类型
字节流
字符流
在以后的开发过程中我们到底使用的是字节流还是字符流?
如果我们操作的是文本文件,那么我们优先考虑字符流.
字节流
字节输入流 InputStream 读
字节输出流 OutputStream 写
字符流
字符输入流 Reader 读
字符输出流 Writer 写
上边的这四个类都是抽象类,不能直接使用,我们只能使用它的子类.并且通过查看API我们可以发现他们的子类都有一个特点: 子类的名称都是一个父类为后缀的
IO流的操作步骤:
a: 创建io流对象
b: 调用方法进行读或者写
c: 释放资源
使用字节输出流写数据:
FileOutputStream
构造方法:
public FileOutputStream(File file) ;
public FileOutputStream(String name) ;
public FileOutputStream(String name , boolean append) ; // 实现追加写
public FileOutputStream(File file , boolean append) ; // 实现追加写
写的成员方法:
public void write(int by) : 一次写一个字节
public void write(byte[] bytes) : 一次写一个字节数组
public void write(byte[] bytes , int off , int len ): 一次写一个字节数组中的一部分
在windows操作系统中的换行符是: "\r\n"
在linux操作系统中的换行是: "\n"
在mac操作系统中的换行是: "\r"
FileInputStream
构造方法:
public FileInputStream(File file) ;
public FileInputStream(String name) ;
读取数据的方法:
public int read(): 一次读取一个字节
public int read(byte[] bytes) : 一次读取一个字节数组 , 返回值表示的意思是: 读取到的有效的字节个数
复制文件:
步骤:
a: 创建字节输入流和字节输出流对象
b: 频繁的读写操作
一次读取一个字节复制文件
一次读取一个字节数组复制文件
c: 释放资源
public static void copyFile() {
// 创建字节输入流和字节输出流对象
FileInputStream fis = new FileInputStream("a.txt") ;
FileOutputStream fos = new FileOutputStream("b.txt");
// 一次读取一个字节复制文件
int by = 0 ;
while((by = fis.read()) != -1){
fos.write(by) ;
}
// 释放资源
fos.close() ;
fis.close() ;
}
public static void copyFile() {
// 创建字节输入流和字节输出流对象
FileInputStream fis = new FileInputStream("a.txt") ;
FileOutputStream fos = new FileOutputStream("b.txt");
// 一次读取一个字节数组复制文件
byte[] bytes = new byte[1024] ;
int len = 0 ;
while((len = fis.read(bytes)) != -1){
fos.write(bytes , 0 , len) ;
}
// 释放资源
fos.close() ;
fis.close() ;
}
高效的字节输入流和高效的字节输出流:
高效的字节输出流: BufferedOutputStream
构造方法: public BufferedOutputStream(OutputStream os) ;
高效的字节输入流: BufferedInputStream
构造方法: public BufferedInputStream(InputStream is) ;
复制文件使用高效的字节输入流和字节输出流:
public static void copyFile() {
// 创建高效的字节输入流和字节输出流对象
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("a.txt")) ;
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("b.txt")) ;
// 一次读取一个字节复制文件
int by = 0 ;
while((by = bis.read()) != -1){
bos.write(by) ;
}
// 释放资源
bos.close() ;
bis.close() ;
}
public static void copyFile() {
// 创建高效的字节输入流和字节输出流对象
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("a.txt")) ;
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("b.txt")) ;
// 一次读取一个字节数组复制文件
byte[] bytes = new byte[1024] ;
int len = 0 ;
while((len = bis.read(bytes)) != -1){
bos.write(byte, 0 , len) ;
}
// 释放资源
bos.close() ;
bis.close() ;
}
字符流
字符流的由来: 为了方便的操作中文.java就提供了字符流
字符流 = 字节流 + 编码表
编码表:
ASCII 'a'-97 , 'A'-65 , '0'-48
GB2312
GBK
UNICODE
UTF-8
------------------------------------------------------------------------------------------------------------------------------
字符串中的编解码问题:
编码: 就是把字符串转换成字节数组
public byte[] getBytes(): 使用平台默认的字符集进行编码
public byte[] getBytes(String charsetName): 可以使用指定的字符集进行编码
解码: 就是把字节数组转换成字符串
public String(byte[] bytes): 使用平台默认的字符集进行解码
public String(byte[] bytes , String charsetName): 可以使用指定的字符集进行解码
编解码问题: 使用什么字符集进行编码,那么就使用什么字符集进行解码
------------------------------------------------------------------------------------------------------------------------------
转换流:
转换输入流(InputStreamReader)
构造方法:
public InputStreamReader(InputStream in);
public InputStreamReader(InputStream in , String charsetName);
成员方法:
public int read(): 一次读取一个字符
public int read(char[] chs): 一次读取一个字符数组,返回值表示的意思是读取到的有效的字符个数
转换输出流(OutputStreamWriter)
构造方法:
public OutputStreamWriter(OutputStream out);
public OutputStreamWriter(OutputStream out , String charsetName) ;
成员方法:
public void write(int ch): 一次写一个字符
public void write(char[] chs): 一次写一个字符数组
public void write(char[] chs , int off , int len): 一次写一个字符数组中的一部分
public void write(String line): 一次写一个字符串
public void write(String line , int off , int len): 一次写一个字符串中的一部分
------------------------------------------------------------------------------------------------------------------------------
便捷类的由来: 由于转换流的名称太长使用起来不是很方便,并且在一般情况下我们也不指定编码表,所有java就提供了针对转换流的便捷类
转换流 便捷类
InputStreamReader FileReader
OutputStreamWriter FileWriter
便捷类没有特有的方法,我们使用它的时候,它的方法是继承自其父类的.
------------------------------------------------------------------------------------------------------------------------------
高效的字符输入流(BufferedReader)
构造方法: public BufferedReader(Reader in) ;
特有的方法: public String readLine(); 一次读取一行
高效的字符输出流(BufferedWriter)
构造方法: public BufferedWriter(Writer w) ;
特有的方法: public void newLine() ; 写入换行符
------------------------------------------------------------------------------------------------------------------------------
IO流的练习
------------------------------------------------------------------------------------------------------------------------------
字符流复制文件的5种方式:
a: 使用便捷类一次读取一个字符复制文件
public static void copyFile() throws IOException {
// 创建对象
FileReader fr = new FileReader("a.txt");
FileWriter fw = new FileWriter("b.txt");
// 一次读取一个字符
int ch = 0 ;
while((ch = fr.read()) != -1) {
fw.write(ch);
}
// 释放资源
fw.close() ;
fr.close() ;
}
b: 使用便捷类一次读取一个字符数组复制文件
public static void copyFile() throws IOException {
// 创建对象
FileReader fr = new FileReader("a.txt");
FileWriter fw = new FileWriter("b.txt");
// 一次读取一个字符
char[] chs = new char[1024] ;
int len = 0 ;
while((len = fr.read(chs)) != -1){
fw.write(chs , 0 , len) ;
}
// 释放资源
fw.close() ;
fr.close() ;
}
c: 使用高效的字符流一次读取一个字符复制文件
public static void copyFile() throws IOException {
// 创建对象
BufferedReader br = new BufferedReader(new FileReader("a.txt")) ;
BufferedWriter bw = new BufferedWriter(new FileWriter("b.txt")) ;
// 一次读取一个字符
int ch = 0 ;
while((ch = br.read()) != -1){
bw.write(ch);
}
// 释放资源
bw.close() ;
br.close() ;
}
d: 使用高效的字符流一次读取一个字符数组复制文件
public static void copyFile() throws IOException {
// 创建对象
BufferedReader br = new BufferedReader(new FileReader("a.txt")) ;
BufferedWriter bw = new BufferedWriter(new FileWriter("b.txt")) ;
// 一次读取一个字符数组
char[] chs = new char[1024] ;
int len = 0 ;
while((len = br.read(chs)) != -1){
bw.write(chs , 0 , len) ;
}
// 释放资源
bw.close() ;
br.close() ;
}
e: 使用高效的字符流一次读取一个文本行复制文件
public static void copyFile() throws IOException {
// 创建对象
BufferedReader br = new BufferedReader(new FileReader("a.txt")) ;
BufferedWriter bw = new BufferedWriter(new FileWriter("b.txt")) ;
// 一次读取一个文本行
String line = null ;
while((line = br.readLine()) != null) {
bw.write(line) ;
bw.newLine() ;
bw.flush() ;
}
// 释放资源
bw.close() ;
br.close() ;
}
------------------------------------------------------------------------------------------------------------------------------
复制多层文件夹
public class CopyFolderDemo {
public static void main(String[] args) throws IOException {
// 封装源路径为一个File对象
File srcFolder = new File("C:\\more") ;
// 封装目的地为一个File对象
File destFolder = new File("E:\\more") ;
// 判断目的地这个File对象是否存在如果不存在就是创建
if(!destFolder.exists()){
destFolder.mkdir() ;
}
copyFolder (srcFolder , destFolder) ;
}
/**
* 复制文件夹
* @param srcFolder
* @param destFolder
* @throws IOException
*/
private static void copyFolder(File srcFolder, File destFolder) throws IOException {
// 获取源路径下所有的文件或者文件夹对应的File数组
File[] files = srcFolder.listFiles() ;
// 遍历
for(File file : files ){
// 判断当前遍历的元素是否是文件
if(file.isFile()) {
// 获取当前遍历的元素的名称
String srcFileName = file.getName() ;
// 构建目标文件
File destFile = new File(destFolder , srcFileName) ;
// 复制文件
copyFile(file , destFile) ;
}else {
// 获取当前文件夹的名称
String srcFolderName = file.getName() ;
// 构建目标文件夹
File newDestFolder = new File(destFolder , srcFolderName) ;
// 判断是是否存在如果不存在就创建
if(!newDestFolder.exists()){
newDestFolder.mkdir() ;
}
// 递归调用
copyFolder(file , newDestFolder) ;
}
}
}
/**
* 复制文件
* @param srcFile
* @param destFile
* @throws IOException
*/
public static void copyFile (File srcFile, File destFile) throws IOException {
// 创建高效的字节输入流和字节输出流对象
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(srcFile)) ;
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(destFile)) ;
// 一次读取一个字节数组进行复制文件
byte[] bytes = new byte[1024] ;
int len = 0 ;
while((len = bis.read(bytes)) != -1){
bos.write(bytes, 0, len) ;
}
// 释放资源
bos.close() ;
bis.close() ;
}
}
------------------------------------------------------------------------------------------------------------------------------
使用Reader自定义类,模拟BufferedReader的readLine()功能并测试
public class MyBufferedReader {
private Reader r ;
public MyBufferedReader(Reader r){
this.r = r ;
}
public String readLine() {
StringBuilder sb = new StringBuilder() ;
int ch = 0 ;
while((ch = r.read()) != -1){
if(ch == '\r') {
continue ;
}
if(ch == '\n') {
return sb.toString() ;
}else {
sb.append((char)ch) ;
}
}
// 为了防止数据的丢失
if(sb.length() > 0 ) {
return sb.toString() ;
}
return null ;
}
public void close() {
r.close() ;
}
}
以上就是IO流最经常用到的字节输入输出流和字符输入输出流以及他们的高效流。当然还有其他的IO流,以后我会再补充。程序没有什么捷径,
只有不断地练习才能不断的进步。共勉。