草庐IT

java - File.length() 在 Java 中返回不正确的值

coder 2024-03-31 原文

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

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

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

以下是环境细节:

  • jdk 1.6.0_24(64位)
  • Java JotSpot(TM) 64 位服务器虚拟机(内部版本 17.0-b17,混合模式)
  • Tomcat 6.0.29
  • window 服务器 2008 r2

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

编辑:

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

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

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

最佳答案

似乎对我来说很好......

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;

        }
    }
}

关于java - File.length() 在 Java 中返回不正确的值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12850312/

有关java - File.length() 在 Java 中返回不正确的值的更多相关文章

  1. ruby - 为什么 4.1%2 使用 Ruby 返回 0.0999999999999996?但是 4.2%2==0.2 - 2

    为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返

  2. ruby-on-rails - 如何使用 instance_variable_set 正确设置实例变量? - 2

    我正在查看instance_variable_set的文档并看到给出的示例代码是这样做的:obj.instance_variable_set(:@instnc_var,"valuefortheinstancevariable")然后允许您在类的任何实例方法中以@instnc_var的形式访问该变量。我想知道为什么在@instnc_var之前需要一个冒号:。冒号有什么作用? 最佳答案 我的第一直觉是告诉你不要使用instance_variable_set除非你真的知道你用它做什么。它本质上是一种元编程工具或绕过实例变量可见性的黑客攻击

  3. ruby-on-rails - rails : save file from URL and save it to Amazon S3 - 2

    从给定URL下载文件并立即将其上传到AmazonS3的更直接的方法是什么(+将有关文件的一些信息保存到数据库中,例如名称、大小等)?现在,我既不使用Paperclip,也不使用Carrierwave。谢谢 最佳答案 简单明了:require'open-uri'require's3'amazon=S3::Service.new(access_key_id:'KEY',secret_access_key:'KEY')bucket=amazon.buckets.find('image_storage')url='http://www.ex

  4. ruby - 无法让 RSpec 工作—— 'require' : cannot load such file - 2

    我花了三天的时间用头撞墙,试图弄清楚为什么简单的“rake”不能通过我的规范文件。如果您遇到这种情况:任何文件夹路径中都不要有空格!。严重地。事实上,从现在开始,您命名的任何内容都没有空格。这是我的控制台输出:(在/Users/*****/Desktop/LearningRuby/learn_ruby)$rake/Users/*******/Desktop/LearningRuby/learn_ruby/00_hello/hello_spec.rb:116:in`require':cannotloadsuchfile--hello(LoadError) 最佳

  5. java - 等价于 Java 中的 Ruby Hash - 2

    我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/

  6. ruby - 如果指定键的值在数组中相同,如何合并哈希 - 2

    我有一个这样的哈希数组:[{:foo=>2,:date=>Sat,01Sep2014},{:foo2=>2,:date=>Sat,02Sep2014},{:foo3=>3,:date=>Sat,01Sep2014},{:foo4=>4,:date=>Sat,03Sep2014},{:foo5=>5,:date=>Sat,02Sep2014}]如果:date相同,我想合并哈希值。我对上面数组的期望是:[{:foo=>2,:foo3=>3,:date=>Sat,01Sep2014},{:foo2=>2,:foo5=>5:date=>Sat,02Sep2014},{:foo4=>4,:dat

  7. ruby - 检查字符串是否包含散列中的任何键并返回它包含的键的值 - 2

    我有一个包含多个键的散列和一个字符串,该字符串不包含散列中的任何键或包含一个键。h={"k1"=>"v1","k2"=>"v2","k3"=>"v3"}s="thisisanexamplestringthatmightoccurwithakeysomewhereinthestringk1(withspecialcharacterslike(^&*$#@!^&&*))"检查s是否包含h中的任何键的最佳方法是什么,如果包含,则返回它包含的键的值?例如,对于上面的h和s的例子,输出应该是v1。编辑:只有字符串是用户定义的。哈希将始终相同。 最佳答案

  8. ruby CSV : How can I read a tab-delimited file? - 2

    CSV.open(name,"r").eachdo|row|putsrowend我得到以下错误:CSV::MalformedCSVErrorUnquotedfieldsdonotallow\ror\n文件名是一个.txt制表符分隔文件。我是专门做的。我有一个.csv文件,我转到excel,并将文件保存为.txt制表符分隔的文件。所以它是制表符分隔的。CSV.open不应该能够读取制表符分隔的文件吗? 最佳答案 尝试像这样指定字段分隔符:CSV.open("name","r",{:col_sep=>"\t"}).eachdo|row|

  9. 使用 ACL 调用 upload_file 时出现 Ruby S3 "Access Denied"错误 - 2

    我正在尝试编写一个将文件上传到AWS并公开该文件的Ruby脚本。我做了以下事情:s3=Aws::S3::Resource.new(credentials:Aws::Credentials.new(KEY,SECRET),region:'us-west-2')obj=s3.bucket('stg-db').object('key')obj.upload_file(filename)这似乎工作正常,除了该文件不是公开可用的,而且我无法获得它的公共(public)URL。但是当我登录到S3时,我可以正常查看我的文件。为了使其公开可用,我将最后一行更改为obj.upload_file(file

  10. ruby - 获取模块中定义的所有常量的值 - 2

    我想获取模块中定义的所有常量的值:moduleLettersA='apple'.freezeB='boy'.freezeendconstants给了我常量的名字:Letters.constants(false)#=>[:A,:B]如何获取它们的值的数组,即["apple","boy"]? 最佳答案 为了做到这一点,请使用mapLetters.constants(false).map&Letters.method(:const_get)这将返回["a","b"]第二种方式:Letters.constants(false).map{|c

随机推荐