碰到难题,有个二进制文件,他实际是许多小文件的组合,其存储结构如下,   
文件头: 长度32 想把它读到char[]里 它的编码方式不是Unicode
列表长度: 长度32 想把它读到int里 假设他是3  就会有3个列表文件名列表文件名1: 长度128 想把它读到char[]里 它的编码方式不是Unicode
列表文件地址1: 长度32 想把它读到int里
列表文件长度1: 长度32 想把它读到int里列表文件名2: 长度128 想把它读到char[]里 它的编码方式不是Unicode
列表文件地址2: 长度32 想把它读到int里
列表文件长度2: 长度32 想把它读到int里列表文件名3: 长度128 想把它读到char[]里 它的编码方式不是Unicode
列表文件地址3: 长度32 想把它读到int里
列表文件长度3: 长度32 想把它读到int里...
剩下的文件的主体,存放的是各个文件的数据,从这些数据里通过列表文件的地址和长度取出小文件。我的目的就是想读取这种文件的数据,能够将小文件读出来,并且在必要的时候能够写入(例如添加一个小文件,这是需要列表长度+1,而且在列表处添加文件的信息,并将文件的数据写入到文件主体)我以前是Delphi的程序员,学Java已经一个多月了,但是用Java读写文件还是似懂非懂,请哪位指点一下,给出所要用的类有哪些和操作的关键代码就行,谢谢。

解决方案 »

  1.   

    用byte[],然后用流写入呗。
      

  2.   

    try {
            BufferedReader in = new BufferedReader(new FileReader("infilename"));
            String str;
            while ((str = in.readLine()) != null) {
                process(str);
            }
            in.close();
        } catch (IOException e) {
        }逻辑方面,还是自己写吧。
      

  3.   

    把文件读到byte数组:    public static byte[] getBytesFromFile(File file) throws IOException {
            InputStream is = new FileInputStream(file);        long length = file.length();        if (length > Integer.MAX_VALUE) {
                // File is too large
            }        byte[] bytes = new byte[(int)length];
        
            // Read in the bytes
            int offset = 0;
            int numRead = 0;
            while (offset < bytes.length
                   && (numRead=is.read(bytes, offset, bytes.length-offset)) >= 0) {
                offset += numRead;
            }
        
            // Ensure all the bytes have been read in
            if (offset < bytes.length) {
                throw new IOException("Could not completely read file "+file.getName());
            }
     
            is.close();
            return bytes;
        }
      

  4.   

    try {
            FileInputStream in = new FileInputStream(new File("infilename"));
            int str;
            while ((str = in.read()) !=-1) {
                process(str);
            }
            in.close();
        } catch (IOException e) {
        }
      

  5.   

    我的目的是根据那些信息的存放位置读出信息,上面好像都没涉及到实现这方面的方法,能不能指点一下如果我知道文件的offset即存放的位置怎么根据信息的已知的长度(大小)取出信息,把文件读入内存我还是会的。
      

  6.   

    刚才查了一下,是不是要用RadomAccessFile做?
      

  7.   

    ??????????????
    就是读文件啊文件头: 长度32 想把它读到char[]里 它的编码方式不是Unicode
    列表长度: 长度32 想把它读到int里 假设他是3  就会有3个列表文件名先不关编码,长度32 你就把前32读了  byte【32】
    在接着读32为啊  然后转为int看是几
    然后
    文件的结构你知道就没问题啊
      

  8.   

    import java.util.*;
    import java.io.*;class SmallFile {
        static final int HEADLEN = 24; //头总长度
        byte[] fileName = new byte[16]; //列表文件名1: 长度128 想把它读到char[]里 它的编码方式不是Unicode。在不确定编码方式的时候,最好直接用byte[]来存放
        int offset; //列表文件地址1: 长度32 想把它读到int里
        int length = -1; //列表文件长度1: 长度32 想把它读到int里
        byte[] content;
        public SmallFile() {    }    public SmallFile(byte[] fn, byte[] content) {
            Arrays.fill(fileName, (byte) 0);
            if (fn != null) {
                if (fn.length <= 16) {
                    System.arraycopy(fn, 0, fileName, 0, fn.length);
                }
                else {
                    System.arraycopy(fn, 0, fileName, 0, 16);
                }
            }
            this.content = content;
            if (content != null) {
                this.length = content.length;
            }
            else {
                this.length = -1;
            }
        }
    }public class ReadBinary {
        static final int HEADLEN = 8; //头总长度
        private String filename;
        private byte[] filehead = new byte[4]; //文件头: 长度32 想把它读到char[]里 它的编码方式不是Unicode
        private int filecount = -1; //列表长度: 长度32 想把它读到int里 假设他是3  就会有3个列表文件名
        private List<SmallFile> files = null;    public void setFilehead(byte[] fh) {
            if (fh == null)
                return;
            Arrays.fill(filehead, (byte) 0);
            if (fh.length <= 4) {
                System.arraycopy(fh, 0, filehead, 0, fh.length);
            }
            else {
                System.arraycopy(fh, 0, filehead, 0, 4);
            }
        }    public ReadBinary(String filename) {
            try {
                readFromFile(filename);
            }
            catch (Exception ex) {
                System.out.println(ex.getMessage());
                System.out.println("在载入数据文件时失败,因此视同为新建一个数据文件!");
                this.filename = filename;
                Arrays.fill(filehead, (byte) 0);
                filecount = 0;
                files = new ArrayList<SmallFile> ();
            }
        }    public void readFromFile(String filename) throws Exception {
            BufferedInputStream bin = new BufferedInputStream(new FileInputStream(
                filename));
            this.filename = filename;
            DataInputStream in = new DataInputStream(bin);
            in.read(filehead); //文件头: 长度32 想把它读到char[]里 它的编码方式不是Unicode
            filecount = in.readInt(); //列表长度: 长度32 想把它读到int里 假设他是3  就会有3个列表文件名
            if (files == null) {
                files = new ArrayList<SmallFile> ();
            }
            else {
                files.clear();
            }
            for (int i = 0; i < filecount; i++) {
                SmallFile file = new SmallFile();
                in.read(file.fileName);
                file.offset = in.readInt(); //列表文件地址1: 长度32 想把它读到int里
                file.length = in.readInt(); //列表文件长度1: 长度32 想把它读到int里
                files.add(file);
            }
        }    public void writeToFile() throws Exception {
            String temp = filename + ".tmp"; //临时文件
            boolean exists = false;
            RandomAccessFile raf = null;
            try {
                raf = new RandomAccessFile(filename, "r"); //文件存在则从文件读入
                exists = true;
            }
            catch (Exception ex) {
                System.out.println("文件不存在,因此启用内存写入模式");
            }
            if (filecount != files.size()) {
                throw new Exception("怪事,居然不相同??");
            }
            DataOutputStream out = new DataOutputStream(new BufferedOutputStream(new
                FileOutputStream(temp)));
            //1、写总文件头
            out.write(filehead);
            out.writeInt(filecount);
            //2、写列表头
            int sumlength = 0;
            for (int i = 0; i < files.size(); i++) {
                SmallFile file = files.get(i);
                out.write(file.fileName);
                if (file.length < 0) {
                    throw new Exception("怪事,文件长度怎么可能小于0?");
                }
                else {
                    out.writeInt(ReadBinary.HEADLEN + SmallFile.HEADLEN * filecount +
                                 sumlength);
                    sumlength += file.length;
                    out.writeInt(file.length);
                }
            }
            //3、写文件内容
            for (int i = 0; i < files.size(); i++) {
                SmallFile file = files.get(i);
                if (file.content != null && (file.length == file.content.length)) {
                    out.write(file.content);
                }
                else if (exists) {
                    raf.seek(file.offset);
                    byte[] b = new byte[file.length];
                    raf.read(b);
                    System.out.println("b:" + new String(b));
                    out.write(b);
                }
                else {
                    throw new Exception("怪事,又不能从内存读,又不能从文件读。这活没法干了!");
                }
            }        out.close();
            if (raf != null) {
                raf.close();
                raf = null;
            }
            System.gc();
            //把原先的文件删除
            File f = new File(filename);
            f.delete();
            //再把临时文件改名到正式文件
            File f2 = new File(temp);
            f2.renameTo(f);
        }    public void addFile(SmallFile file) {
            if (files != null) {
                filecount++;
                files.add(file);
            }
        }
        
        public static void test1(){
            ReadBinary rb = new ReadBinary("f:\\temp\\rb.dat");
            rb.setFilehead("HEAD1234567890122222222222222222".getBytes());
            SmallFile f = new SmallFile("第1个文件".getBytes(), "第1个文件的内容".getBytes());
            rb.addFile(f);
            try {
                rb.writeToFile();
            }
            catch (Exception ex) {
                ex.printStackTrace();
            }
        }
        
        public static void test2(){
            ReadBinary rb = new ReadBinary("f:\\temp\\rb.dat");
            rb.setFilehead("HEA".getBytes());
            SmallFile f = new SmallFile("第2个文件".getBytes(), "第2个文件的内容".getBytes());
            rb.addFile(f);
            try {
                rb.writeToFile();
            }
            catch (Exception ex) {
                ex.printStackTrace();
            }
        }
        
        public static void main(String[] args) {
            //test1();
            test2();
        }
    }
      

  9.   

    我可以推荐你去了解一下java里的java.nio包下的FileChannel类方法结合视图缓冲区技术就可以满足你的需求了,试试吧,呵呵!!!
      

  10.   


    //package com.ricky.www
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.nio.channels.FileChannel;
    import java.nio.ByteBuffer;public class Test{
    public static void main(String[] args)throws IOException{
    /**
    *这里假设要将Total.bin的前10个字节写入ricky.bin
    *将后12个字节写入jennie.bin
    */
    separate();
    } private static void separate()throws IOException{
    File total = new File("Total.bin");
    File ricky = new File("ricky.bin");
    File jennie = new File("jennie.bin"); FileInputStream fis = new FileInputStream(total);
    FileOutputStream fos1 = new FileOutputStream(ricky);
    FileOutputStream fos2 =  new FileOutputStream(jennie);
    FileChannel tChannel = fis.getChannel();
    FileChannel rChannel = fos1.getChannel();
    FileChannel jChannel = fos2.getChannel(); ByteBuffer buffer1 = ByteBuffer.allocate(10); //这里指定缓冲区大小
    ByteBuffer buffer2 = ByteBuffer.allocate(12); tChannel.read(buffer1);
    tChannel.read(buffer2); buffer1.flip();
    buffer2.flip(); rChannel.write(buffer1);
    jChannel.write(buffer2); fis.close();
    fos1.close();
    fos2.close();
    }
    }
      

  11.   

    http://www.5fuyou.com/images/head/DownLoad.html 分享一个编程视频下载地址,很好,很强大
      

  12.   

      我觉得用FileChannel这个类好些。ByteBuffer中刚好有getInt,get等方法。
      

  13.   

    读的话,用 DataInputStream FileInputStream 就可以了。
    想要写的话, 要用到 RandomAccessFile添加新文件的方法:
    如果里面有三个小文件,你想写第四个小文件。因为都是顺序写入,头没有剩余空间。那你可以先把第一个小文件读出来写到文件尾,然后更新第一个文件的地址,就可以把小文件原来的空间当作头来写了。写完之后,再更新头所表示的小文件数目。(为了安全性,写的顺序有一定讲究)以下是读的实例代码:public class CustomFile {    public CustomFile(File file) throws FileNotFoundException, IOException {
            DataInputStream in = null;
            try {
                in = new DataInputStream(new FileInputStream(file));            head = new char[]{in.readChar(), in.readChar()};            infos = new FileInfo[in.readInt()];
                
                for (int i = 0; i < infos.length; i++) {
                    infos[i] = new FileInfo(file, in);
                }
            } finally {
                if (in != null) {
                    try {
                        in.close();
                    } catch (IOException ex) {
                        Logger.getLogger(CustomFile.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }
            }
        }
        public char[] head;
        public FileInfo[] infos;    public static class FileInfo {        private FileInfo(File file, DataInputStream in) throws IOException {
                this.file = file;
                name = new char[8];
                for (int i = 0; i < name.length; i++) {
                    name[i] = in.readChar();
                }
                address = in.readInt();
                length = in.readInt();
            }        public InputStream getInputStream() throws IOException {
                InputStream in = new FileInputStream(file);
                in.skip(address);
                return new _InputStream(in, length);
            }
            private File file;
            public char[] name;
            public int address;
            public int length;
        }    private static class _InputStream extends InputStream {        public _InputStream(InputStream in, int length) {
                this.in = in;
                this.length = length;
            }        @Override
            public int read() throws IOException {
                if (length <= 0) {
                    return -1;
                } else {
                    length--;
                    return in.read();
                }
            }        @Override
            public void close() throws IOException {
                in.close();
            }
            private InputStream in;
            private int length;
        }
    }
      

  14.   


    import java.io.BufferedInputStream;
    import java.io.BufferedOutputStream;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    public class DiskTest {
        public static void main(String[] args) throws Exception {
            // TODO Auto-generated method stub
            File file = new File("D:\\picture.rar");
            byte[] content=readFile(file);
            System.out.println(content);
            writeBytes("D:\\picture1.rar",content);
        }    /** *//**读文件到字节数组
         * @param file
         * @return
         * @throws Exception
         */
        static byte[] readFile(File file) throws   Exception {
            if (file.exists() && file.isFile()) {
                long fileLength = file.length();
                if (fileLength > 0L) {
                    BufferedInputStream fis = new BufferedInputStream(
                            new FileInputStream(file));
                    byte[] b = new byte[(int) fileLength];
                    while (fis.read(b)!= -1) {
                    }
                    fis.close();
                    fis = null;                return b;
                }
            } else {
                return null;
            }
            return null;
        }    /** *//**将字节数组写入文件
         * @param filePath
         * @param content
         * @return
         * @throws IOException
         */
        static boolean writeBytes(String filePath, byte[] content)
                throws IOException {
            File file = new File(filePath);
            synchronized (file) {
                BufferedOutputStream fos = new BufferedOutputStream(
                        new FileOutputStream(filePath));
                fos.write(content);
                fos.flush();
                fos.close();
            }
            return true;    }
    }