设计用于从文件中的标题数据确定文件扩展名

时间:2015-05-23 07:31:35

标签: java arraylist nodes

我有一个问题,我一直试图将我的头脑包裹两天,并且没有在网上找到任何东西(或在这里),所以我想我会发布这个问题,看看我有什么样的反馈意见得到。我在业余时间编写了一个小程序,它扫描文件目录(删除了文件扩展名)并读取每个文件的文件头,以便找出每个文件的文件扩展名。到目前为止,我已经使用了一系列if / else if语句来满足"模式匹配"我的计划的功能......

private String fileHeaderCheck()
{
    /* ----- PNG File Type Verification ----- */
    if (headerCheck.buffer[0] == 0x89 && headerCheck.buffer[1] == 0x50 && headerCheck.buffer[2] == 0x4E && headerCheck.buffer[3] == 0x47
        && headerCheck.buffer[4] == 0xD && headerCheck.buffer[5] == 0xA && headerCheck.buffer[6] == 0x1A && headerCheck.buffer[7] == 0xA)
    {
        return ".png";
    }

    /* ----- JPG File Type Verification ----- */
    else if (headerCheck.buffer[0] == 0xFF && headerCheck.buffer[1] == 0xD8 && headerCheck.buffer[2] == 0xFF && headerCheck.buffer[3] == 0xE0)
    {
        return ".jpg";
    }

    // And so on and so on through the whole list of file types I am checking for

    else
        return "unknown";           
}

headerCheck是一个Buffer对象,它包含一个byte [],用于保存从文件的前512个字节读入的数据。我在这个模式匹配过程中加入了25-30种不同的文件类型,因此您可以看到该函数将很快变得庞大和丑陋。我想要做的是使用Node对象的ArrayList,每个对象包含:1。特定文件类型的标题信息的字节[],以及2.表示文件扩展类型的字符串, 然后只是遍历数组,比较Node byte []和headerCheck.buffer [],无论匹配什么元素,我都会将它的fileType附加到我在headerCheck.buffer []中读取的文件的末尾。从。我的Node类以这种方式设置....

class Node  //if this is the "png" Node 
{
    byte[] metadata;
    String fileType;

    Node()
    {
        this.metadata = new byte[]{0x89, 0x50, 0x4E, 0x47, 0xD, 0xA, 0x1A, 0xA};
        this.fileType = ".png";
    }
}

我无法弄清楚如何初始化ArrayList。我是否必须使用预配置的数据创建/实例化25-30个单独的节点类,以初始化ArrayList,然后将()添加到它?这似乎比所有if / else if语句或开关更糟糕......第二个问题是,一旦我使用所有Node对象实例化我的ArrayList,我就无法直观地看到如何迭代它的byte []为了将它与headerCheck.buffer []进行比较。我正在推动我的知识界限所以对于这些问题,我没有代码,因为我不知道从哪里开始编码这些东西。我正在考虑使用双嵌套for循环,但我还没有达到那么远,因为我还没有找到一种初始化ArrayList的有效方法。我甚至考虑过一些设计模式作为可能的补救措施,但无济于事。任何帮助将不胜感激...谢谢

迭代方法(沿着这些方向):

boolean match;

for (int x = 0; x < pattens.get(metadata).size(); x++)
{
    if (headerCheck.buffer[x] != patterns.get(metadata[x])
    {
        match = false;
        return;
    }   
    else
        return true;
}

2 个答案:

答案 0 :(得分:1)

您使用的是一种非常复杂的方法,导致代码难以维护。如果你可以改进整个设计,我想提出一个如下的替代方法:

创建名为 FileExtension的接口:

interface FileExtension {
    public String getExtension(byte[] buffer);
}

创建包含用于确定文件扩展名的逻辑的类:

class PNGExtension implements FileExtension {

    @Override
    public String getExtension(byte[] buffer) {
        /* ----- PNG File Type Verification ----- */
        String fileType = null;
        if (buffer[0] == 0x89 && buffer[1] == 0x50 && buffer[2] == 0x4E && buffer[3] == 0x47 && buffer[4] == 0xD && buffer[5] == 0xA
                && buffer[6] == 0x1A && buffer[7] == 0xA) {
            fileType = ".png";
        }

        return fileType;
    }

}

class JPGExtension implements FileExtension {

    @Override
    public String getExtension(byte[] buffer) {
        /* ----- JPG File Type Verification ----- */
        String fileType = null;
        if (buffer[0] == 0xFF && buffer[1] == 0xD8 && buffer[2] == 0xFF && buffer[3] == 0xE0) {
            fileType = ".jpg";
        }

        return fileType;
    }

}

创建一个最终将用于根据前512个字节获取文件扩展名的复合具体类

class CompositeFileExtension implements FileExtension {

    private List<FileExtension> fileExtensions;

    public CompositeFileExtension() {
        //in the real world, this list can be populated through an IoC container
        fileExtensions = new ArrayList<FileExtension>();
        fileExtensions.add(new PNGExtension());
        fileExtensions.add(new JPGExtension());

    }

    @Override
    public String getExtension(byte[] buffer) {
        String fileExtension = null;
        for(FileExtension extension : fileExtensions) {
            if((fileExtension=extension.getExtension(buffer))!=null) {
                break;
            }
        }

        return fileExtension;
    }
}

最后,放在一起的所有代码片段将按如下方式工作:

public class FileMapperDemo {
    public static void main(String[] args) {
        /*
         * 1. For each file in directory
         *    2. Read first 512 bytes into buffer array
         *       3. Create a new CompositeFileExtension object and pass it the buffer
         * 
         */

                     CompositeFileExtension fileExtensions = new CompositeFileExtension();

                     //4. get the file extension 
                     String fileExtension = fileExtensions.getExtension(buffer);

    }
}

这种方法的优点是,只要需要从缓冲区推导出新类型的文件扩展名,您只需要向FileExtension添加新的ArrayList个对象。您不需要创建两个类似的byte数组(您可以在example.One中创建两个字节数组,用于从数组中读取的前512个字节,另一个用于与此数组进行比较)

答案 1 :(得分:0)

您可以将节点类更改为以下内容:

class FilePattern {
    byte[] metadata ;
    String extension ;

    public FilePattern(byte[] m, String ext) {
        this.metadata = m ;
        this.extension = ext ;
    }

    /* add the getters here */
}

现在,您可以在向其添加元素时初始化ArrayList,即

ArrayList<FilePattern> patterns = new ArrayList<FilePattern>();
patterns.add(new FilePattern(new byte[]{ ... }, "extension"));
.... // for other patterns.

接下来,循环遍历patterns的元素,提取元数据字节并与从文件读取的字节匹配并确定文件类型。

修改:对于循环,您可以执行以下操作:

for(FilePattern f : patterns)
    if(Arrays.equals(f.getMetadata(), headerCheck.buffer))
        System.out.println("Found file with extension : ", f.getExtension());