Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/368.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何检查文件是否为二进制文件?_Java_File_Binary_Ascii - Fatal编程技术网

Java 如何检查文件是否为二进制文件?

Java 如何检查文件是否为二进制文件?,java,file,binary,ascii,Java,File,Binary,Ascii,我编写了以下方法,以查看特定文件是否仅包含ASCII文本字符,还是除此之外还包含控制字符。你能看一下这个代码,提出改进建议并指出疏忽吗 逻辑如下:“如果文件的前500个字节包含5个或更多控制字符,请将其报告为二进制文件” 多谢各位 public boolean isAsciiText(String fileName) throws IOException { InputStream in = new FileInputStream(fileName); byte[] bytes

我编写了以下方法,以查看特定文件是否仅包含ASCII文本字符,还是除此之外还包含控制字符。你能看一下这个代码,提出改进建议并指出疏忽吗

逻辑如下:“如果文件的前500个字节包含5个或更多控制字符,请将其报告为二进制文件”

多谢各位

public boolean isAsciiText(String fileName) throws IOException {

    InputStream in = new FileInputStream(fileName);
    byte[] bytes = new byte[500];

    in.read(bytes, 0, bytes.length);
    int x = 0;
    short bin = 0;

    for (byte thisByte : bytes) {
        char it = (char) thisByte;
        if (!Character.isWhitespace(it) && Character.isISOControl(it)) {

            bin++;
        }
        if (bin >= 5) {
            return false;
        }
        x++;
    }
    in.close();
    return true;
}

x
似乎没有任何作用

如果文件小于500字节怎么办

某些二进制文件的情况是,您可以为文件的前N个字节设置一个头,其中包含一些对应用程序有用的数据,但二进制文件所在的库并不关心这些数据。您可以很容易地在这样的前导码中包含500+字节的ASCII码,然后在接下来的千兆字节中包含二进制数据


如果文件无法打开或读取,则应处理异常,等等。

我注意到的第一件事-与您的实际问题无关,但您应该在
finally
块中关闭输入流,以确保始终完成。通常这只处理异常,但在您的情况下,当返回
false
时,您甚至不会关闭文件流

旁白:为什么要与ISO控制字符进行比较?这不是“二进制”文件,而是“包含5个或更多控制字符的文件”。在我看来,更好的方法是反转check-write一个
isAsciiText
函数,该函数断言文件中的所有字符(或前500个字节中的字符,如果您愿意的话)都在一组已知良好的字节中

理论上,如果文件是某种类型的复合文件(例如,带有嵌入图片的文本),仅检查文件的前几百个字节可能会让您陷入麻烦,但实际上,我怀疑每一个这样的文件在开始时都会有二进制头数据,因此您可能没有问题

  • 忽略read()返回的内容,如果文件小于500字节怎么办
  • 如果返回false,则不会关闭该文件
  • 将字节转换为字符时,假定文件是7位ASCII 由于您将这个类称为“isASCIIText”,所以您确切地知道自己在寻找什么。换句话说,它不是“IStextinirentLocaleEncoding”。因此,您可以更准确地使用:

    if (thisByte < 32 || thisByte > 127) bin++;
    
    if(thisByte<32 | | thisByte>127)bin++;
    

    编辑,很长一段时间之后——在一篇评论中指出,这个简单的检查会被一个以许多新行开头的文本文件绊倒。最好使用一个包含“ok”字节的表,并包含可打印字符(包括回车符、换行符和制表符,可能还有表单提要,尽管我不认为许多现代文档都使用这些字符),然后检查该表。

    这不适用于linux或solaris的jdk安装包。它们有一个shell脚本开始,然后是一个bi数据blob

    为什么不使用一些库来检查mime类型,比如jMimeMagic()和基于mimetype的deside如何处理文件

  • 如果文件大小小于500字节,则会严重失败

  • charit=(char)thisByte
    在概念上是可疑的,它混合了字节和字符概念,即隐式假设编码是一个字节=一个字符(它们不包括unicode编码)。特别是,如果文件是UTF-16编码的,则会失败

  • 循环内的返回(在IMO中有点糟糕)忘记关闭文件


  • 您可以解析和比较ageinst中的已知二进制文件头字节列表,例如

    问题是,需要一个只包含二进制头的排序列表,而这个列表可能根本不完整。例如,读取和解析某些Equinox框架jar中包含的二进制文件。但是,如果需要识别特定的文件类型,这应该是可行的

    如果您在Linux上,对于磁盘上的现有文件,本机应该可以正常工作:

    String command = "file -i [ZIP FILE...]";
    Process process = Runtime.getRuntime().exec(command);
    ...
    
    它将输出有关文件的信息:

    ...: application/zip; charset=binary
    
    您可以使用grep或Java对其进行进一步过滤,这取决于您是否只需要估计文件的二进制字符,或者您是否需要找出它们的
    MIME
    类型

    不幸的是,如果解析输入流(如归档文件中嵌套文件的内容),这将不起作用,除非求助于纯shell程序(如
    unzip
    ),以避免创建临时解压缩文件

    对于这一点,到目前为止,对检查前500个字节的粗略估计对我来说还可以,正如上面的例子所暗示的那样;我使用了
    Character.isWhitespace/isISOControl(char)
    ,而不是
    Character.isIdentifierIgnorable(codePoint)
    ,假设
    UTF-8
    默认编码:

    private static boolean isBinaryFileHeader(byte[] headerBytes) {
        return new String(headerBytes).codePoints().filter(Character::isIdentifierIgnorable).count() >= 5;
    }
    
    public void printNestedZipContent(String zipPath) {
        try (ZipFile zipFile = new ZipFile(zipPath)) {
            int zipHeaderBytesLen = 500;
            zipFile.entries().asIterator().forEachRemaining( entry -> {
                String entryName = entry.getName();
                if (entry.isDirectory()) {
                    System.out.println("FOLDER_NAME: " + entryName);
                    return;
                }
                // Get content bytes from ZipFile for ZipEntry 
                try (InputStream zipEntryStream = new BufferedInputStream(zipFile.getInputStream(zipEntry))) {
                    // read and store header bytes
                    byte[] headerBytes = zipEntryStream.readNBytes(zipHeaderBytesLen);
                    // Skip entry, if nested binary file
                    if (isBinaryFileHeader(headerBytes)) {
                        return;
                    }
                    // Continue reading zipInputStream bytes, if non-binary
                    byte[] zipContentBytes = zipEntryStream.readAllBytes();
                    int zipContentBytesLen = zipContentBytes.length;
                    // Join already read header bytes and rest of content bytes
                    byte[] joinedZipEntryContent = Arrays.copyOf(zipContentBytes, zipContentBytesLen + zipHeaderBytesLen);
                    System.arraycopy(headerBytes, 0, joinedZipEntryContent, zipContentBytesLen, zipHeaderBytesLen);
                    // Output (default/UTF-8) encoded text file content
                    System.out.println(new String(joinedZipEntryContent));
                } catch (IOException e) {
                    System.out.println("ERROR getting ZipEntry content: " + entry.getName());
                }
            });
        } catch (IOException e) {
            System.out.println("ERROR opening ZipFile: " + zipPath);
            e.printStackTrace();
        }
    }
    

    不幸的是,当此算法将包含“this\r\nis\r\nonly\r\ntext”的文件分类为二进制文件时,将其标记为正确答案。@Ingo-true;最好检查控制字符与非控制字符的比例,并检查文本中常见的控制字符等特殊情况。当我输入这个答案时,我太年轻了:)