字节流 | 字符流 | |||
抽象父类 | InputStream(read方法:有参参作容,无参返作容) int read() 读取一字节到int低八位并返回此int(0-255),返回-1表示EOF。 int read(byte[] b) 读取批量字节到指定数组,返回实际读取量,返回-1表示EOF。 int read(byte[] b, int off, int len) 读取len字节到指定数组,从数组off处开始, 返回实际读取量,返回-1表示EOF。 long skip(long n) 跳过n字节不读,返回实际跳过字节数。 void close() 关闭流 OutputStream(write方法:皆有参无返,参数皆容器) void write(int b) 写出指定int值的低八位(一个字节) void write(byte[] b) 写出指定字节数组中的所有字节 void write(byte[] b, int off, int len) 写出指定数组中off处开始的len个字节 void flush() 刷新流 void close() 关闭流 | Reader(read方法:有参参作容,无参返作容) int read() 读取一字符到int低十六位并返回此int(0-65535), 返回-1表示EOF。 int read(char[] chs) 读取批量字符到指定数组,返回实际读取量,返回-1表示EOF。 Int read(char[] cbuf, int off, int len) 读取len字符到指定数组,从数组off处开始, 返回实际读取量,返回-1表示EOF。 long skip(long n) 跳过n字符不读,返回实际跳过字节数。 void close() 关闭流 Writer(write方法:皆有参无返,参数皆容器) void write(int c) 写出指定int值的低十六位(一个字符) void write(char[] chuf) 写出指定字符数组中的所有字符 void write(char[] chuf, int off, int len) 写出指定数组中off处开始的len个字符 void write(String str) 写出指定字符串的所有字符 void write(String str, int off, int len) 写出指定字符串中off处开始的len个字符 void flush() 刷新流 void close() 关闭流 | ||
文件流 | FileInputStream (File file) (String name) FileOutputStream (File file) 重写模式 (File file, true) 追加模式append (String name) 重写模式 (String name, true) 追加模式append | FileReader (File file) (String name) FileWriter (File file) 重写模式 (File file, true) 追加模式append (String name) 重写模式 (String name, true) 追加模式append | ||
管道流 | PipedInputStream PipedOutputStream | PipedReader PipedWriter | ||
数组流 | ByteArrayInputStream (byte[] buf) (读入指定数组为缓冲区数组) (byte[] buf, int offset, int length) (读入指定数组为缓冲区数组) int available() 返回可从此输入流读出(或跳过)的剩余字节数。 void close() 关闭 ByteArrayInputStream 无效。 void mark(int readAheadLimit) 设置流中的当前标记位置。 boolean markSupported() 测试此 InputStream 是否支持 mark/reset。 int read() 从流中读出下一字节到新int并返回。返回-1表示EOS int read(byte[] b, int off, int len) 将最多len字节从流中读出到指定数组off处始。 返回实际读出量,返回-1表示EOS void reset() 将指针重置为标记位置 long skip(long n) 从流中跳过n字节 ByteArrayOutputStream () 无参构造 (int size) (指定size字节大小的缓冲区容量) void close() 关闭 ByteArrayOutputStream 无效。 void reset() 将流中指针重置为0从而丢弃已累积的输出 int size() 返回缓冲区的当前大小。 byte[] toByteArray() 将流中数据写出到新数组并返回 String toString() 将流中数据写出到默认解码的新字符串中并返回 String toString(String charsetName) 将流中数据写出到指定解码的新字符串中并返回 void write(byte[] b, int off, int len) 将指定数组中off处开始的len个字节写入此流 void write(int b) 将指定字节写入此流 void writeTo(OutputStream out) 将流中数据写出到指定输出流 | CharArrayReader CharArrayWriter | ||
数据流 | DataInputStream (OutputStream out) 基本类型 read基本类型() 指针越过并读取基本类型字节到基本类型并返回,EOF则抛异常。 String readUTF() 读入一个已使用 UTF-8 修改版格式编码的字符串 static String readUTF(DataInput in) 从流 in 中读取并返回用 UTF-8 修改版格式编码的 Unicode 字符格式的字符串 int skipBytes(int n) 指针跳过n字节不读,返回实际跳过字节数,若n为负,则不跳过任何字节。 DataOutputStream (OutputStream out) void write基本类型(基本类型 jblx) 指针写出指定基本类型数据并越过基本类型字节 void writeBytes(String s) 将字符串按字节顺序写出到基础输出流中 void writeChars(String s) 将字符串按字符顺序写入基础输出流 void writeUTF(String str) 以与机器无关方式使用 UTF-8 修改版编码将一个字符串写入基础输出流。 int size() 返回已写入此流的字节数。 | 字符串流 | StringReader StringWriter | |
缓冲流 | BufferedInputStream (InputStream in) (InputStream in, int size) BufferedOutputStream (OutputStream out) (OutputStream out, int size) | BufferedReader (Reader in) (Reader in, int sz) String readLine() 读一行,返回null表EOF。 BufferedWriter (Writer out) (Writer out, int sz) void newLine() 换行 | ||
对象流 | ObjectInputStream (InputStream in) Object readObject() 对象反序列化 ObjectOutputStream (OutputStream out) void writeObject(Object o) 对象序列化 | 转换流 | InputStreamReader (InputStream in) (InputStream in,String charsetName) (自定义字符集) String getEncoding() 返回此流字符集 OutputStreamWriter (OutputStream out) (OutputStream out,String charsetName) (自定义字符集) String getEncoding() 返回此流字符集 | |
打印流 | PrintStream (File file) (File file, String csn) (自定义字符集) (String fileName) (String fileName, String csn) (自定义字符集) (OutputStream out) (OutputStream out, true) (自动行刷新autoFlush) (OutputStream out, true, String encoding) (自动行刷新autoFlush)(自定义字符集) System.out.print() System.out.println() | PrintWriter (File file) (File file, String charsetName) (自定义字符集) (String fileName) (String filename, String charsetName) (自定义字符集) (OutputStream out) (OutputStream out, true) (自动行刷新autoFlush) (Writer out) (Writer out, true) (自动行刷新autoFlush) void print(除byte/short外各种类型) void println() 换行 void println(除byte/short外各种数据类型) | ||
备注 | 节点流:文件流、管道流、数组流、字符串流 处理流:缓冲流、对象流、转换流、打印流、数据流 数组转字符串: public String(byte bytes[]) public String(byte bytes[], String charsetName) public String(byte bytes[], int offset, int length) public String(byte bytes[], int offset, int length, String charsetName) public String(char value[]) public String(char value[], int offset, int count) 字符串转byte数组: public byte[] getBytes() public byte[] getBytes(String charsetName) public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin)(包头不包尾) |
文件下载示例:
/** * 下载Excel模板 */ @PostMapping("/template") public void template(HttpServletResponse response) { try { InputStream fis = this.getClass().getResourceAsStream("/file/excelTemplate.xlsx"); response.setContentType("application/force-download"); response.addHeader("Content-disposition", "attachment;fileName=" + URLEncoder.encode("Excel模板.xlsx", "UTF-8")); OutputStream os = response.getOutputStream(); byte[] buf = new byte[1024]; int len = 0; while((len = fis.read(buf)) != -1) { os.write(buf, 0, len); } fis.close(); } catch (IOException e) { throw new FxRuntimeException("下载Excel模板失败", e); } } |
文件字节流和缓冲字节流
package com.tongwx.io; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; public class FileAndBufferedStreamDemo { public static void main(String[] args) throws IOException { write(); read(); //writeWhileReading(); } /** * 写 */ private static void write() throws IOException { OutputStream outputStream = null; //outputStream = new FileOutputStream("E:\\write.txt", true);使用文件流。true:追加写入模式 outputStream = new BufferedOutputStream(new FileOutputStream("E:\\write.txt"));可外加缓冲流,必须刷新或关闭流才能写入文件 String str = "千寻铁锁沉江底\n一片降幡出石头";//Windows下换行是\r\n byte[] b = str.getBytes(); outputStream.write(b); outputStream.close(); } /** * 读 * @throws IOException */ private static void read() throws IOException { InputStream inputStream = null; //inputStream = new FileInputStream("E:\\GenerateFileTree.txt");//使用文件流 inputStream = new BufferedInputStream(new FileInputStream("E:\\write.txt"));//可外加缓冲流 byte[] b = new byte[1024]; int actualLength; while ((actualLength = inputStream.read(b, 0, b.length)) != -1) { String str = new String(b, 0, actualLength, "utf-8"); System.out.print(str); } inputStream.close(); } /** * 边读边写(文件复制) */ private static void writeWhileReading() { } } |
package com.tongwx.io; import java.io.FileWriter; import java.io.IOException; public class FileWtriterDemo { /** * 写 */ public static void main(String[] args) throws IOException { FileWriter fileWriter = new FileWriter("src/com/tongwx/io/resource/test.txt"); String str = "Hello World!"; fileWriter.write(str);//输出字符串 fileWriter.write("\r\n"); char[] bs = new char[str.length()]; str.getChars(0, str.length(), bs, 0);//前二参包头不包尾 fileWriter.write(bs);//输出字符数组 fileWriter.close(); } } |
package com.tongwx.io; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.FileOutputStream; import java.io.IOException; public class ByteArrayStreamDemo { public static void main(String[] args) throws IOException { byte[] bytes = "Hello World!".getBytes(); ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);//数组转输入流 int container; while (-1 != (container = byteArrayInputStream.read())) {//输入流转int System.out.print((char) container); } System.out.println("\n------------------------1"); byteArrayInputStream.reset();//将缓冲区的位置重置为标记位置。若未标记或未指定偏移量,则重置为 0。 byte[] bs = new byte[1024]; while (-1 != byteArrayInputStream.read(bs, 0, bs.length)) {//输入流转数组 for (byte b : bs) { System.out.print((char) b); } } System.out.println("\n------------------------2"); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); byteArrayOutputStream.write(bytes);//数组转输出流 byte[] byteArray = byteArrayOutputStream.toByteArray();//输出流转数组 for (byte b : byteArray) { System.out.print((char) b); } System.out.println("\n------------------------3"); String string = byteArrayOutputStream.toString();//输出流转字符串 System.out.println(string); System.out.println("------------------------4"); FileOutputStream fileOutputStream = new FileOutputStream("E:/fuck.txt", true); byteArrayOutputStream.writeTo(fileOutputStream);//输出流借助文件输出流转为文件 byteArrayOutputStream.close();//关闭流无效 fileOutputStream.close(); } } |
package com.tongwx.io; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; public class DataStreamDemo { public static void main(String[] args) throws IOException { write();//写 read();//读(必须按写的顺序读回来!) } /** * 写 */ private static void write() throws IOException { DataOutputStream dataOutputStream = new DataOutputStream(new FileOutputStream("E:/fuck")); dataOutputStream.write(0); dataOutputStream.writeByte(1); dataOutputStream.writeShort(2); dataOutputStream.writeInt(3); dataOutputStream.writeLong(4); dataOutputStream.writeFloat(5); dataOutputStream.writeDouble(6); dataOutputStream.writeBoolean(true); dataOutputStream.writeChar(97); dataOutputStream.close(); } /** * 读(必须按写的顺序读回来!) */ private static void read() throws IOException { DataInputStream dataInputStream = new DataInputStream(new FileInputStream("E:/fuck")); System.out.println(dataInputStream.read()); System.out.println(dataInputStream.readByte()); System.out.println(dataInputStream.readShort()); System.out.println(dataInputStream.readInt()); System.out.println(dataInputStream.readLong()); System.out.println(dataInputStream.readFloat()); System.out.println(dataInputStream.readDouble()); System.out.println(dataInputStream.readBoolean()); System.out.println(dataInputStream.readChar()); dataInputStream.close(); } } |
package com.tongwx.io; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; public class SteamAndBufferedReaderAndWriterDemo { public static void main(String[] args) throws IOException { testOutputStreamReaderAndBufferedReader(); testInputStreamReaderAndBufferedReader(); } private static void testOutputStreamReaderAndBufferedReader() throws IOException { // BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("E:/test.txt"))); //Java项目中文件流访问项目内文件的路径形式从限定名的src处开始写 BufferedWriter writer = new BufferedWriter(new FileWriter("src/com/tongwx/io/resource/test.txt")); writer.write("千山鸟飞绝"); writer.newLine();Windows下换行是\r\n writer.write("万径人踪灭"); writer.write("\n孤舟蓑笠翁\n独钓寒江雪");Windows下换行是\r\n writer.close(); } public static void testInputStreamReaderAndBufferedReader() throws IOException { // BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream("E:/test.txt"))); //Java项目中文件流访问项目内文件的路径形式从限定名的src处开始写 BufferedReader reader = new BufferedReader(new FileReader("src/com/tongwx/io/resource/test.txt")); String str = null; while (null != (str = reader.readLine())) { System.out.println(str); } reader.close(); } } |
package com.tongwx.io; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; public class PrintStreamDemo { public static void main(String[] args) throws IOException { BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); String str = null; while (null != (str = reader.readLine())) { System.out.println(str); } reader.close(); } } |
File类常用方法
构造方法和字段:
File(String pathname) 构造方法
File(String parent,String child) 构造方法
File(File parent,String child) 构造方法
static String pathSeparator 与系统有关的路径分隔符,为了方便,它被表示为一个字符串。(: 或 ;)
static char pathSeparatorChar 与系统有关的路径分隔符。(: 或 ;)
static String separator 与系统有关的默认名称分隔符,为了方便,它被表示为一个字符串。(/ 或 \\)
static char separatorChar 与系统有关的默认名称分隔符。(/ 或 \\)
判断:
boolean exists() 判断文件或目录是否存在
boolean isFile() 判断是否为文件
boolean isDirectory() 判断是否为目录
boolean isHidden() 判断是否为隐藏
boolean isAbsolute() 判断是否为绝对路径
创建:
boolean createNewFile() 创建空文件,成功返回true,已有或父目录不存在则返回false
boolean mkdir() 创建目录,成功返回true,父目录不存在返回false,被安全管理器拒绝则抛异常
boolean mkdirs() 创建多层目录,全部创建才返true,已有返回false,被安全管理器拒绝则抛异常
删除:(谨慎操作,没有后悔药吃)
boolean delete() 删除文件或空目录,成功返回true,失败返回false
void deleteOnExit() 虚拟机退出时删除文件或空目录,无返回值
修改:
boolean renameTo(File dest) 重命名文件或目录。路径不同时将同时移动,但不能重命名目录到不同盘符。文件不存在时该方法无效。成功返回true,失败返回false
获取:
String getName() 返回文件名或目录名
String getPath() 返回定义时的路径名
String getAbsolutePath() 返回绝对路径名
String getCanonicalPath() 返回规范路径名(移除.和..及盘符大写等)
String getParent() 返回父目录的路径名,若未指定父目录,则返回null
File getParentFile() 返回父目录的抽象路径名,若未指定父目录,则返回null
long length() 返回文件长度(字节数)。若为目录,永远是0
long lastModified() 返回最后一次被修改的时间
String[] list() 获取目录下所有子项到String数组
String[] list(FilenameFilter filter) 获取目录下所有满足过滤规则的子项到String数组
File[] listFiles() 获取目录下所有子项到File数组
File[] listFiles(FileFilter filter) 获取目录下所有满足过滤规则的子项到File数组
File[] listFiles(FilenameFilter filter) 获取目录下所有满足过滤规则的子项到File数组
使用FileFilter / FilenameFilter过滤文件:用匿名内部类实现FileFilter / FilenameFilter接口的抽象方法accept(...)
//列出后缀名为.tmp的文件 public static void main(String[] args) throws IOException { File file = new File("B:/"); File[] files = file.listFiles(new FileFilter() { @Override public boolean accept(File pathname) { return pathname.isFile() && pathname.getName().endsWith(".tmp"); } }); for (File f : files) { System.out.println(f); } } |
生成文件目录
生成目录列表
package encode; import java.io.File; import java.io.FileNotFoundException; import java.io.PrintStream; public class GenerateFileList { public static void main(String[] args) throws FileNotFoundException { PrintStream out = new PrintStream("E:/GenerateFileList.txt"); System.setOut(out); File dir = new File("H:/"); if (!dir.exists() || !dir.isDirectory()) { throw new IllegalArgumentException(dir + " 不是目录或此目录不存在!"); } System.out.println(dir.getPath()); generateFileList(dir); } public static void generateFileList(File dir) { File[] files = dir.listFiles(); if (null != files) { for (File file : files) { System.out.println(file.getPath()); if (file.isDirectory()) { generateFileList(file); } } } } } |
生成目录树(粗糙版)
package encode; import java.io.File; import java.io.FileNotFoundException; import java.io.PrintStream; public class GenerateFileTree { public static void main(String[] args) throws FileNotFoundException { PrintStream out = new PrintStream("E:/GenerateFileTree.txt"); System.setOut(out); File dir = new File("H:/"); if (!dir.exists() || !dir.isDirectory()) { throw new IllegalArgumentException(dir + " 不是目录或此目录不存在!"); } System.out.println(dir.getPath()); generateFileTree(dir, "├ "); } public static void generateFileTree(File dir, String space) { File[] files = dir.listFiles(); if (null != files) { for (File file : files) { System.out.println(space + file.getName()); if (file.isDirectory()) { generateFileTree(file, "│ " + space); } } } } } |
package com.tongwx.io.listfile; import java.io.File; public class LIstFolder { public static void main(String[] args) { File file = new File("B:/0/新建文件夹"); listFolder(file, "├ "); } public static void listFolder(File file, String table) { System.out.println(table + file.getName()); if (file.isDirectory()) { File[] listFiles = file.listFiles(); for (File file2 : listFiles) { listFolder(file2, "| " + table); } } } } |
生成目录树
package encode; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.PrintStream; import java.util.Stack; public class FileTree { public static void main(String[] args) throws FileNotFoundException { PrintStream out = new PrintStream("E:/tree.txt"); System.setOut(out); FileTree tree = new FileTree("H:/"); tree.tree(); out.close(); } private File root; public FileTree(File root) { this.root = root; } public FileTree(String rootName) { this(new File(rootName)); } public void tree() { Stack<Boolean> lastStack = new Stack<Boolean>(); tree(root, 0, lastStack); } private void tree(File dir, int level, Stack<Boolean> lastStack) { if (dir == null || !dir.exists()) { return; } printFile(dir, level, lastStack); if (dir.isFile()) { return; } File[] children = dir.listFiles(); if (null != children) { for (int i = 0; i < children.length; i++) { lastStack.push(i == children.length - 1); tree(children[i], level + 1, lastStack); lastStack.pop(); } } } private void printFile(File file, int level, Stack<Boolean> lastStack) { for (int i = 0, k = lastStack.size() - 1; i < k; i++) { System.out.print(lastStack.get(i) ? " " : "│ ");// 一个全角空格加一个半角空格 } if (level > 0) { System.out.print(lastStack.get(lastStack.size() - 1) ? "└ " : "├ "); } try { if (level == 0) { System.out.println(file.getPath() + " " + formatFileSize(getFileSize(file))); } else { System.out.println(file.getName() + " " + formatFileSize(getFileSize(file))); } } catch (IOException e) { e.printStackTrace(); } } public static String formatFileSize(double d) { if (d < 1024) { return (short) d + "B"; } else if (d / 1024 < 1024) { return Math.round(d / 1024.0) + "KB"; } else if (d / 1024 / 1024 < 1024) { return Math.round(d / 1024.0 / 1024.0) + "MB"; } else { return String.format("%.2f", d / 1024.0 / 1024.0 / 1024.0) + "GB"; } } public static double getFileSize(File file) throws IOException { if (!file.exists()) { return 0.0; } if (!file.isFile()) { File[] fl = file.listFiles(); double ss = 0; if (null != fl) { for (File f : fl) { ss += getFileSize(f); } } return ss; } else { return file.length(); } } } |
生成资源浏览器
import java.awt.BorderLayout; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.io.File; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTree; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.TreePath; public class ExplorerTree extends JPanel { private JTree tree;//创建默认的树 private TreePath treePath;//路径 int t=0; public ExplorerTree() {
this.setLayout(new BorderLayout()); DefaultMutableTreeNode root = new DefaultMutableTreeNode("我的计算机");//设置跟节点 tree = new JTree(root); File[] roots = File.listRoots(); for (int i = 0; i < roots.length; i++) { DefaultMutableTreeNode node = new DefaultMutableTreeNode(roots[i].getPath()); root.add(node);//增加到根节点 } MouseListener ml = new MouseAdapter() { public void mousePressed(MouseEvent e) { try { TreePath tp = tree.getPathForLocation(e.getX(), e.getY()); String ttt=tp.getLastPathComponent().toString(); System.out.println(ttt+"#############"); System.out.println("----------->"+tp); if (tp != null) { treePath = tp; int size = treePath.getPath().length; System.out.println("------>"+size); StringBuffer pathname = new StringBuffer(); if (size > 0) { File file = new File(ttt+"\\"); File[] list = file.listFiles(); for (int i = 0; i < list.length; i++) { String[] strings = list[i].getPath().split(""); for(int j=0;j<strings.length;j++){ System.out.println(strings[j]+"%%%%%%%%%%%%%%%%%%%%"); } DefaultMutableTreeNode node = new DefaultMutableTreeNode(strings[strings.length - 1]); ((DefaultMutableTreeNode) tp.getLastPathComponent()).add(node); } } } } catch (Exception e1) { System.out.println("can not open"); } } }; tree.addMouseListener(ml); tree.setShowsRootHandles(true); tree.setRootVisible(true); JScrollPane scrPane = new JScrollPane(tree); add(scrPane); } public static void main(String[] args) { JFrame jFrame = new JFrame("Explorer"); jFrame.setLayout(new BorderLayout()); jFrame.add(new ExplorerTree()); jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); jFrame.setSize(300, 700); jFrame.setVisible(true); } } |
加密文件
import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; public class Encryption { public static void main(String[] args) { //找到目标文件 File inFile = new File("E:\\还原.jpg"); File outFile = new File("E:\\加密.jpg"); //File inFile = new File("E:\\加密.jpg"); //File outFile = new File("E:\\还原.jpg"); //建立数据的输入通道 FileInputStream input = null; FileOutputStream out = null; try { input = new FileInputStream(inFile); out = new FileOutputStream(outFile); //边读边写 int content = 0; while ((content = input.read()) != -1) { out.write(content ^ 123); } } catch (IOException e) { e.printStackTrace(); } finally { try { //关闭资源 if (null != out) { out.close(); } } catch (IOException e) { e.printStackTrace(); } finally { try { input.close(); } catch (IOException e) { e.printStackTrace(); } } } } } |
清空/删除文件夹
package com.tongwx.io; import java.io.File; public class DeleteFolder { public static void main(String[] args) { File file = new File("H:\\编程临时文件 - 副本"); clearFolder(file); } //清空非空文件夹或删除空文件夹 public static void clearFolder(File file) { if (file.isFile() || file.list().length == 0) { file.delete(); } else { File[] files = file.listFiles(); for (File subFile : files) { clearFolder(subFile); subFile.delete(); } } } } |
RandomAccessFile没有继承自IO流,直接继承自Object,但和数据流一样实现了DataInput, DataOutput,所以和数据流的用法类似。
RandomAccessFile类常用方法
RandomAccessFile(File file, String mode) 构造方法(mode参数值有 r、rw等)
RandomAccessFile(String name, String mode) 构造方法(mode参数值有 r、rw等)
int read() 指针越过并读取一字节到int的低八位(0-255)并返回int,返回-1表示EOF。
基本类型 read基本类型() 指针越过并读取基本类型字节到基本类型并返回,EOF则抛异常。
int read(byte[] b) 指针越过并读取批量字节到指定数组,返回实际读取量,返回-1表示EOF。
int read(byte[] b, int off, int len) 指针越过并读取len字节到指定数组,从数组off处开始,返回实际读取量,返回-1表示EOF。
void write(int b) 指针写出指定int值的低八位并越过一字节
void write基本类型(基本类型 jblx) 指针写出指定基本类型数据并越过基本类型字节
void writeBytes(String s) 按字节序列将指定字符串写入该文件并越过等长字节
void writeChars(String s) 按字符序列将指定字符串写入该文件并越过等长字节
void writeUTF(String str) 使用 modified UTF-8 编码以与机器无关的方式将指定字符串写入该文件并越过指定字符串编码后字节+2字节(首先,把两个字节从文件的当前文件指针写入到此文件,类似于使用 writeShort 方法并给定要跟随的字节数。此值是实际写出的字节数,而不是该字符串的长度。在该长度之后,按顺序输出该字符串的每个字符,并对每个字符使用 UTF-8 修改版编码。)
void write(byte[] b) 指针写出并越过指定字节数组中的所有字节
void write(byte[] b,int off,int len) 指针写出并越过指定数组中off处开始的len个字节
int skipBytes(int n) 指针跳过n字节不读,返回实际跳过字节数,若n为负,则不跳过任何字节。
void close() 关闭流
long getFilePointer() 获取指针当前位置
void seek(long pos) 移动指针到指定位置
package com.tongwx.io; import java.io.IOException; import java.io.RandomAccessFile; public class RandomAccessFileDemo { public static void main(String[] args) throws IOException { RandomAccessFile randomAccessFile = new RandomAccessFile("src/com/tongwx/io/resource/test", "rw"); Person person = new Person("zhangsan", 20, 1.75); person.write(randomAccessFile); Person substitute = new Person(); randomAccessFile.seek(0);//读取前要重置指针 substitute.read(randomAccessFile); System.out.println(substitute); } } class Person { private String name; private int age; private double height; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public double getHeight() { return height; } public void setHeight(double height) { this.height = height; } public Person() { } public Person(String name, int age, double height) { super(); this.name = name; this.age = age; this.height = height; } @Override public String toString() { return "Person [name=" + name + ", age=" + age + ", height=" + height + "]"; } public void write(RandomAccessFile raf) throws IOException { raf.writeUTF(name); raf.writeInt(age); raf.writeDouble(height); } public void read(RandomAccessFile raf) throws IOException { name = raf.readUTF(); age = raf.readInt(); height = raf.readDouble(); } } |
package com.tongwx.io; import java.nio.charset.Charset; import java.util.Set; import java.util.SortedMap; public class testCharset { public static void main(String[] args) { SortedMap<String, Charset> availableCharsets = Charset.availableCharsets(); Set<String> keySet = availableCharsets.keySet(); for (String string : keySet) { System.out.println(string + "=" + availableCharsets.get(string)); } } } |
概念
•把对象写到字节流里的过程是序列化(Serilization)过程,而把对象从字节流中读出来的过程则叫做反序列化(Deserialization)过程。应当指出的是,写在流里的是对象的一个拷贝,而原对象仍然存在于JVM里面。
•将一个对象保存到永久存储设备上称为持久化。
•一个对象要想能够实现序列化,必须实现Serializable接口或Externalizable接口。
当一个对象被序列化时,只保存对象的非静态成员变量,不能保存任何的成员方法和静态的成员变量。
如果一个对象的成员变量是一个对象,那么这个对象的数据成员也会被保存。
如果一个可序列化的对象包含对某个不可序列化的对象的引用,那么整个序列化操作将会失败,并且会抛出一个NotSerializableException。我们可以将这个引用标记为transient,那么对象仍然可以序列化。
如果一个类可以序列化,它的所有子类都可以序列化。
声明成transient的变量不被序列化工具存储。同样,static变量也不被存储
ObjectOutputStream和ObjectInputStream
•ObjectOutput接口继承DataOutput接口并且支持对象序列化,其实现类为ObjectOutputStream。
void writeObject(Object obj) 将对象写入底层存储或流。方法出错时引发IOException异常
•ObjectInput接口继承DataInput接口并且支持对象反序列化,其实现类为ObjectInputStream。
Object readObject() 读取并返回对象。方法出错时引发IOException异常
自定义序列化和反序列化
在序列化和反序列化进程中需要特殊处理的 Serializable 类应该成对实现以下方法:
• private void writeObject(java.io.ObjectOutputStream stream)
throws IOException;
• private void readObject(java.io.ObjectInputStream stream)
throws IOException, ClassNotFoundException;
这两个方法不属于任何一个类和任何一个接口,是非常特殊的方法。
关于serialVersionUID
•当一个类实现了Serializable接口时,表明该类可被序列化,此时Eclipse会要求你为该类定义一个long类型的名为serialVersionUID的字段。
•你可以随便写一个,在Eclipse中它可替你生成一个,有两种生成方式:一个是默认的1L,一个是根据类名、接口名、成员方法及属性等来生成一个64位的哈希字段。
•如果你不考虑兼容性问题时,可在Eclipse的设置中取消警告:Window ==> Preferences ==> Java ==> Compiler ==> Error/Warnings ==> Potential programming problems 将Serializable class without serialVersionUID的warning改成ignore即可。
•如果你考虑兼容性问题时,应当定义它。这个serialVersionUID为了让该类序列化时能向后兼容:当你将对象序列化后更改了类的field(增加或减少或改名),在反序列化时,如果没有serialVersionUID或者serialVersionUID不一致,就会出现异常,这样就造成了兼容性问题;而当serialVersionUID相同时,它就会将不一样的field以type的缺省值反序列化,这个可以避开不兼容性的问题。
package com.tongwx.io; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; public class SerializableDemo { public static void main(String[] args) throws IOException, ClassNotFoundException { /** * 序列化 */ ObjectOutputStream objectOutputStream = new ObjectOutputStream( new FileOutputStream("src/com/tongwx/io/resource/test.txt")); Student student1 = new Student("zhangsan", 20, 1.75, "吃喝"); Student student2 = new Student("lisi", 21, 1.76, "交友"); Student student3 = new Student("wangwu", 22, 1.77, "竞技"); objectOutputStream.writeObject(student1); objectOutputStream.writeObject(student2); objectOutputStream.writeObject(student3); objectOutputStream.close(); /** * 反序列化 */ ObjectInputStream objectInputStream = new ObjectInputStream( new FileInputStream("src/com/tongwx/io/resource/test.txt")); Student s1 = (Student) objectInputStream.readObject(); Student s2 = (Student) objectInputStream.readObject(); Student s3 = (Student) objectInputStream.readObject(); System.out.println(s1); System.out.println(s2); System.out.println(s3); objectInputStream.close(); } } class Student implements Serializable { private static final long serialVersionUID = 1; private String name; private int age; private double height; private transient String secret;//transient修饰的不会被序列化 public Student(String name, int age, double height, String secret) { super(); this.name = name; this.age = age; this.height = height; this.secret = secret; } public Student() { super(); } @Override public String toString() { return "Person [name=" + name + ", age=" + age + ", height=" + height + ", secret=" + secret + "]"; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public double getHeight() { return height; } public void setHeight(double height) { this.height = height; } public String getSecret() { return secret; } public void setSecret(String secret) { this.secret = secret; } /** * 自定义序列化方法必须实现的方法(必须与自定义反序列化方法成对出现) */ private void writeObject(java.io.ObjectOutputStream out) throws IOException { out.writeUTF(name); } /** * 自定义反序列化方法必须实现的方法(必须与自定义序列化方法成对出现) */ private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { name = in.readUTF(); } } |
浅复制与深复制概念
-浅复制(浅克隆):被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。换言之,浅复制仅仅复制所考虑的对象,而不复制它所引用的对象。
-深复制(深克隆):被复制对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量。那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象。换言之,深复制把要复制的对象所引用的对象都复制了一遍。
Object类的clone()方法(浅克隆)
•clone方法将对象复制了一份并返回给调用者。一般而言,clone()方法满足:
①对任何的对象x,都有x.clone() !=x(克隆对象与原对象不是同一个对象)
②对任何的对象x,都有x.clone().getClass()==x.getClass()(克隆对象与原对象的类型一样)
③如果对象x的equals()方法定义恰当,那么x.clone().equals(x)应该成立。
浅克隆的步骤:
•派生类实现Cloneable接口,覆盖Object的clone()方法,并声明为public的(原Object类中的clone()方法为protected的),且一定要调用super.clone()。
•在合适的地方调用派生类的clone()方法:类型 新对象引用 = (强转类型)原对象引用.clone();
•为什么我们在派生类中覆盖Object的clone()方法时,一定要调用super.clone()呢?
在运行时刻,Object中的clone()识别出你要复制的是哪一个对象,然后为此对象分配空间,并进行对象的复制,将原始对象的内容一一复制到新对象的存储空间中。
Object类的clone()方法(深克隆)
见代码,不建议使用,麻烦。
利用序列化来做深克隆
•先使该类实现Serializable接口,然后把对象(实际上只是对象的一个拷贝)写到一个流里,再从流里读出来,便可以重建对象。
•这样做的前提是对象以及对象内部所有引用到的对象都是可串行化的,否则,就需要仔细考察那些不可串行化的对象可否设成transient,从而将之排除在复制过程之外。
•注意:Cloneable与Serializable都是marker Interface(标识接口),没有定义任何方法。
package com.tongwx.io; public class TestShallowClone { public static void main(String[] args) throws CloneNotSupportedException { Pupil pupil = new Pupil("zhangsan", 10, new Teacher("zs", 25)); Pupil clone = (Pupil) pupil.clone(); System.out.println(pupil);//Student [name=zhangsan, age=10, t=Teacher [name=zs, age=25]] System.out.println(clone);//Student [name=zhangsan, age=10, t=Teacher [name=zs, age=25]] System.out.println(clone == pupil);//false System.out.println(clone.getTeacher() == pupil.getTeacher());//true clone.setName("lisi");//改克隆的字符串属性不影响原对象 clone.setAge(11);//改克隆的基本类型属性不影响原对象 System.out.println(pupil);//Student [name=zhangsan, age=10, t=Teacher [name=zs, age=25]] System.out.println(clone);//Student [name=lisi, age=11, t=Teacher [name=zs, age=25]] System.out.println(clone == pupil);//false,克隆不等于原对象 System.out.println(clone.getTeacher() == pupil.getTeacher());//true,浅复制中克隆所引用的对象等于原对象所引用的对象 clone.getTeacher().setName("ls");//对克隆所引用的对象的修改就是对原对象所引用的对象的修改 clone.getTeacher().setAge(26);//对克隆所引用的对象的修改就是对原对象所引用的对象的修改 System.out.println(pupil);//Student [name=zhangsan, age=10, t=Teacher [name=ls, age=26]] System.out.println(clone);//Student [name=lisi, age=11, t=Teacher [name=ls, age=26]] System.out.println(clone == pupil);//false,克隆不等于原对象 System.out.println(clone.getTeacher() == pupil.getTeacher());//true,浅复制中克隆所引用的对象等于原对象所引用的对象 clone.setTeacher(new Teacher("ls", 26));//引用了新对象,不再指向原对象所引用的对象 System.out.println(pupil);//Student [name=zhangsan, age=10, t=Teacher [name=ls, age=26]] System.out.println(clone);//Student [name=lisi, age=11, t=Teacher [name=ls, age=26]] System.out.println(clone == pupil);//false,克隆不等于原对象 System.out.println(clone.getTeacher() == pupil.getTeacher());//false,,浅复制中克隆的成员变量引用了新对象导致所引用的对象不等于原对象所引用的对象 } } class Pupil implements Cloneable { private String name; private int age; private Teacher teacher; /** * 浅复制(只复制了对象) */ @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } /** * 深复制(复制了对象和对象所引用的对象) */ // @Override // public Object clone() throws CloneNotSupportedException { // Pupil pupil = (Pupil) super.clone(); // pupil.setTeacher((Teacher) teacher.clone()); // return pupil; // } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Teacher getTeacher() { return teacher; } public void setTeacher(Teacher t) { this.teacher = t; } public Pupil(String name, int age, Teacher t) { super(); this.name = name; this.age = age; this.teacher = t; } @Override public String toString() { return "Student [name=" + name + ", age=" + age + ", t=" + teacher + "]"; } } class Teacher implements Cloneable { private String name; private int age; @Override public Object clone() throws CloneNotSupportedException { return super.clone(); } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Teacher(String name, int age) { super(); this.name = name; this.age = age; } @Override public String toString() { return "Teacher [name=" + name + ", age=" + age + "]"; } } |
package com.tongwx.io; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; /** * 对象深克隆 */ public class TestDeepClone { public static void main(String[] args) throws IOException, ClassNotFoundException { //原父亲 Father father = new Father("zhangsan", 40, new Son("zhangsi", 20)); //深克隆父亲 Father deepCloneFather = (Father) father.deepClone(); //换身份 deepCloneFather.setName("隔壁老王"); deepCloneFather.setAge(50); deepCloneFather.getSon().setName("隔壁小王"); deepCloneFather.getSon().setAge(30); System.out.println(father);//Father [name=zhangsan, age=40, son=Son [name=zhangsi, age=20]] System.out.println(deepCloneFather);//Father [name=隔壁老王, age=50, son=Son [name=隔壁小王, age=30]] System.out.println(father == deepCloneFather);//不是亲生父亲 } } class Father implements Serializable { private static final long serialVersionUID = 1L; private String name; private int age; private Son son; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Son getSon() { return son; } public void setSon(Son son) { this.son = son; } public Father(String name, int age, Son son) { super(); this.name = name; this.age = age; this.son = son; } @Override public String toString() { return "Father [name=" + name + ", age=" + age + ", son=" + son + "]"; } /** * 深复制(将对象序列化到字节流中再反序列化返回一份给调用者) */ public Object deepClone() throws IOException, ClassNotFoundException { ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(this);//将当前对象通过oos写入bos ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());//将bos转为bis ObjectInputStream ois = new ObjectInputStream(bis); return ois.readObject();//通过ois从bis读取当前对象并提供给调用者 } } class Son implements Serializable { private static final long serialVersionUID = 1L; private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Son(String name, int age) { super(); this.name = name; this.age = age; } @Override public String toString() { return "Son [name=" + name + ", age=" + age + "]"; } } |