6

在文件对象上调用 .length() 时,超过 2 GB 的文件返回不正确的值。

这发生在运行在 tomcat 容器中的 Web 应用程序中。

例如,windows 报告为 2,083,344,714 字节的文件从 java 中返回为 1887961088。

以下是环境细节:

  • jdk 1.6.0_24(64位)
  • Java JotSpot(TM) 64 位服务器 VM(内部版本 17.0-b17,混合模式)
  • 雄猫 6.0.29
  • 视窗服务器 2008 r2

所以我立即怀疑与 32 位虚拟机有关,但一切似乎都在 64 位运行。我完全被难住了,任何帮助将不胜感激,只要帮助开发一些测试,看看问题是否与以某种方式在 32 模式下运行的东西有关..

编辑:

回答一些评论:当我使用相同的 JVM(仅输出 file.length)运行一个非常简单的测试用例时,我得到了正确的值:2,083,344,714。

我非常有信心这应该可以工作,我只是觉得我的 tomcat 配置/java 配置/应用程序让我很难过。它仅影响超过一定大小的文件这一事实确实使它看起来像是 32 位与 64 位的问题,但据我所知,一切都是 64 位的。

编辑 2:开始怀疑这几乎是不可能的,我可能会遇到一个问题,即线程在文件被完全复制之前占用了文件的长度。如果有人在乎,我会在我弄清楚时在这里发布:-)

4

1 回答 1

5

对我来说似乎工作得很好......

Windows 7 x64 上的 pagefile.sys,由 DOS 报告为 8446545920 字节

Java 7.0_02 x32 8446545920 / 7.87 GB

Java 1.6_30 x32 8446545920 / 7.87 GB

import java.io.File;
import java.text.NumberFormat;

public class TestFileSize {

    public static void main(String[] args) {
        File test1 = new File("C:/pagefile.sys");
        File test2 = new File("C:/hiberfil.sys");

        System.out.println(test1.length() + " / " + ByteFormatter.format(test1.length()));
        System.out.println(test2.length() + " / " + ByteFormatter.format(test2.length()));

    }

    public static class ByteFormatter {

        public static final long KILO_BYTES = 1024;
        public static final long MEGA_BYTES = 1024 * KILO_BYTES;
        public static final long GIGA_BYTES = 1024 * MEGA_BYTES;
        public static final long TERA_BYTES = 1024 * GIGA_BYTES;
        public enum Format {

            TeraBytes(TERA_BYTES),
            GigaBytes(GIGA_BYTES),
            MegaBytes(MEGA_BYTES),
            KiloBytes(KILO_BYTES);
            private long multiplier;

            private Format(long multiplier) {
                this.multiplier = multiplier;
            }

            public long getMultiplier() {
                return multiplier;
            }
        }

        public static String format(long bytes) {
            NumberFormat nf = NumberFormat.getNumberInstance();
            nf.setMaximumFractionDigits(2);
            nf.setMinimumFractionDigits(0);
            String format = bytes + " bytes";
            if (bytes / TERA_BYTES > 0) {
                format = nf.format((double) bytes / TERA_BYTES) + " tb";
            } else if (bytes / GIGA_BYTES > 0) {
                format = nf.format((double) bytes / GIGA_BYTES) + " gb";
            } else if (bytes / MEGA_BYTES > 0) {
                format = nf.format((double) bytes / MEGA_BYTES) + " mb";
            } else if (bytes / KILO_BYTES > 0) {
                format = nf.format((double) bytes / KILO_BYTES) + " kb";
            } else {
                format = nf.format(bytes) + " bytes";
            }

            return format;
        }

        public static String formatMegaBytes(long lMegaBytes) {

            return format((long) ((double) lMegaBytes * MEGA_BYTES));

        }

        public static String formatKiloBytes(long kbytes) {

            return format(kbytes * KILO_BYTES);

        }

        public static String formatGigaBytes(long gbytes) {

            return format(gbytes * GIGA_BYTES);

        }

        public static String formatTeraBytes(long gbytes) {

            return format(gbytes * TERA_BYTES);

        }

        public static long toBytes(String value, Format format) {

            long multipler = format.getMultiplier();

            long bytes = (long) (Double.parseDouble(value.trim()) * multipler);

            return bytes;

        }

        public static long toBytes(String sValue) {

            long lBytes = 0;

            if (sValue.indexOf(" ") > -1) {

                String sElements[] = sValue.split(" ");

                lBytes = Long.parseLong(sElements[0]);

                if (sElements[1].toLowerCase().startsWith("gb")) {

                    lBytes *= GIGA_BYTES;

                } else if (sElements[1].toLowerCase().startsWith("mb")) {

                    lBytes *= MEGA_BYTES;

                } else if (sElements[1].toLowerCase().startsWith("kb")) {

                    lBytes *= KILO_BYTES;

                }

            } else {

                sValue = sValue.trim();
                long lMultiplier = 1;
                String sBytes = null;

                if (sValue.toLowerCase().endsWith("gb")) {

                    sBytes = sValue.substring(0, sValue.toLowerCase().indexOf("gb"));
                    lMultiplier = GIGA_BYTES;

                } else if (sValue.toLowerCase().endsWith("mb")) {

                    sBytes = sValue.substring(0, sValue.toLowerCase().indexOf("mb"));
                    lMultiplier = MEGA_BYTES;

                } else if (sValue.toLowerCase().endsWith("kb")) {

                    sBytes = sValue.substring(0, sValue.toLowerCase().indexOf("kb"));
                    lMultiplier = KILO_BYTES;

                }

                lBytes = Long.parseLong(sBytes);

                lBytes *= lMultiplier;

            }

            return lBytes;

        }
    }
}
于 2012-10-12T00:19:19.377 回答