File::Stat 類別
File::Stat
類別的物件封裝 File
物件的常見狀態資訊。此資訊會在建立 File::Stat
物件時記錄下來;此後對檔案所做的變更將不會反映在其中。 File::Stat
物件會由 IO#stat
、File::stat
、File#lstat
和 File::lstat
傳回。其中許多方法會傳回特定於平台的值,而且並非所有值在所有系統中都有意義。另請參閱 Kernel#test
。
公開類別方法
File::Stat.new(file_name) -> stat
針對指定的檔案名稱建立 File::Stat
物件(如果檔案不存在,則會引發例外狀況)。
static VALUE rb_stat_init(VALUE obj, VALUE fname) { struct stat st; FilePathValue(fname); fname = rb_str_encode_ospath(fname); if (STAT(StringValueCStr(fname), &st) == -1) { rb_sys_fail_path(fname); } struct rb_stat *rb_st; TypedData_Get_Struct(obj, struct rb_stat, &stat_data_type, rb_st); rb_st->stat = st; rb_st->initialized = true; return Qnil; }
公開實例方法
透過比較 File::Stat
物件的修改時間來比較這些物件。
如果 other_stat
不是 File::Stat
物件,則會傳回 nil
f1 = File.new("f1", "w") sleep 1 f2 = File.new("f2", "w") f1.stat <=> f2.stat #=> -1
static VALUE rb_stat_cmp(VALUE self, VALUE other) { if (rb_obj_is_kind_of(other, rb_obj_class(self))) { struct timespec ts1 = stat_mtimespec(get_stat(self)); struct timespec ts2 = stat_mtimespec(get_stat(other)); if (ts1.tv_sec == ts2.tv_sec) { if (ts1.tv_nsec == ts2.tv_nsec) return INT2FIX(0); if (ts1.tv_nsec < ts2.tv_nsec) return INT2FIX(-1); return INT2FIX(1); } if (ts1.tv_sec < ts2.tv_sec) return INT2FIX(-1); return INT2FIX(1); } return Qnil; }
傳回此檔案的最後存取時間,為 Time
類別的物件。
File.stat("testfile").atime #=> Wed Dec 31 18:00:00 CST 1969
static VALUE rb_stat_atime(VALUE self) { return stat_atime(get_stat(self)); }
傳回 stat 的出生時間。
如果平台沒有出生時間,則會引發 NotImplementedError
。
File.write("testfile", "foo") sleep 10 File.write("testfile", "bar") sleep 10 File.chmod(0644, "testfile") sleep 10 File.read("testfile") File.stat("testfile").birthtime #=> 2014-02-24 11:19:17 +0900 File.stat("testfile").mtime #=> 2014-02-24 11:19:27 +0900 File.stat("testfile").ctime #=> 2014-02-24 11:19:37 +0900 File.stat("testfile").atime #=> 2014-02-24 11:19:47 +0900
static VALUE rb_stat_birthtime(VALUE self) { return stat_birthtime(get_stat(self)); }
傳回本機檔案系統的區塊大小。在不支援此資訊的平台上會傳回 nil
。
File.stat("testfile").blksize #=> 4096
static VALUE rb_stat_blksize(VALUE self) { #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE return ULONG2NUM(get_stat(self)->st_blksize); #else return Qnil; #endif }
如果檔案是區塊裝置,則傳回 true
;如果檔案不是區塊裝置或作業系統不支援此功能,則傳回 false
。
File.stat("testfile").blockdev? #=> false File.stat("/dev/hda1").blockdev? #=> true
static VALUE rb_stat_b(VALUE obj) { #ifdef S_ISBLK if (S_ISBLK(get_stat(obj)->st_mode)) return Qtrue; #endif return Qfalse; }
傳回配置給此檔案的本機檔案系統區塊數目,或在作業系統不支援此功能時傳回 nil
。
File.stat("testfile").blocks #=> 2
static VALUE rb_stat_blocks(VALUE self) { #ifdef HAVE_STRUCT_STAT_ST_BLOCKS # if SIZEOF_STRUCT_STAT_ST_BLOCKS > SIZEOF_LONG return ULL2NUM(get_stat(self)->st_blocks); # else return ULONG2NUM(get_stat(self)->st_blocks); # endif #else return Qnil; #endif }
如果檔案是字元裝置,則傳回 true
;如果檔案不是字元裝置或作業系統不支援此功能,則傳回 false
。
File.stat("/dev/tty").chardev? #=> true
static VALUE rb_stat_c(VALUE obj) { if (S_ISCHR(get_stat(obj)->st_mode)) return Qtrue; return Qfalse; }
傳回 stat 的變更時間(也就是檔案目錄資訊的變更時間,而非檔案本身的變更時間)。
請注意,在 Windows(NTFS)上,會傳回建立時間(出生時間)。
File.stat("testfile").ctime #=> Wed Apr 09 08:53:14 CDT 2003
static VALUE rb_stat_ctime(VALUE self) { return stat_ctime(get_stat(self)); }
傳回表示 stat 所在裝置的整數。
File.stat("testfile").dev #=> 774
static VALUE rb_stat_dev(VALUE self) { #if SIZEOF_STRUCT_STAT_ST_DEV <= SIZEOF_DEV_T return DEVT2NUM(get_stat(self)->st_dev); #elif SIZEOF_STRUCT_STAT_ST_DEV <= SIZEOF_LONG return ULONG2NUM(get_stat(self)->st_dev); #else return ULL2NUM(get_stat(self)->st_dev); #endif }
傳回 File_Stat#dev
的主要部分或 nil
。
File.stat("/dev/fd1").dev_major #=> 2 File.stat("/dev/tty").dev_major #=> 5
static VALUE rb_stat_dev_major(VALUE self) { #if defined(major) return UINT2NUM(major(get_stat(self)->st_dev)); #else return Qnil; #endif }
傳回 File_Stat#dev
的次要部分或 nil
。
File.stat("/dev/fd1").dev_minor #=> 1 File.stat("/dev/tty").dev_minor #=> 0
static VALUE rb_stat_dev_minor(VALUE self) { #if defined(minor) return UINT2NUM(minor(get_stat(self)->st_dev)); #else return Qnil; #endif }
如果 stat 是目錄,則傳回 true
;否則傳回 false
。
File.stat("testfile").directory? #=> false File.stat(".").directory? #=> true
static VALUE rb_stat_d(VALUE obj) { if (S_ISDIR(get_stat(obj)->st_mode)) return Qtrue; return Qfalse; }
如果 stat 可執行,或作業系統無法區分可執行檔案與不可執行檔案,則傳回 true
。測試使用程序的有效擁有者進行。
File.stat("testfile").executable? #=> false
static VALUE rb_stat_x(VALUE obj) { struct stat *st = get_stat(obj); #ifdef USE_GETEUID if (geteuid() == 0) { return RBOOL(st->st_mode & S_IXUGO); } #endif #ifdef S_IXUSR if (rb_stat_owned(obj)) return RBOOL(st->st_mode & S_IXUSR); #endif #ifdef S_IXGRP if (rb_stat_grpowned(obj)) return RBOOL(st->st_mode & S_IXGRP); #endif #ifdef S_IXOTH if (!(st->st_mode & S_IXOTH)) return Qfalse; #endif return Qtrue; }
與 executable?
相同,但使用程序的實際擁有者進行測試。
static VALUE rb_stat_X(VALUE obj) { struct stat *st = get_stat(obj); #ifdef USE_GETEUID if (getuid() == 0) { return RBOOL(st->st_mode & S_IXUGO); } #endif #ifdef S_IXUSR if (rb_stat_rowned(obj)) return RBOOL(st->st_mode & S_IXUSR); #endif #ifdef S_IXGRP if (rb_group_member(get_stat(obj)->st_gid)) return RBOOL(st->st_mode & S_IXGRP); #endif #ifdef S_IXOTH if (!(st->st_mode & S_IXOTH)) return Qfalse; #endif return Qtrue; }
如果 stat 是常規檔案(不是裝置檔案、管線、socket 等),則傳回 true
。
File.stat("testfile").file? #=> true
static VALUE rb_stat_f(VALUE obj) { if (S_ISREG(get_stat(obj)->st_mode)) return Qtrue; return Qfalse; }
識別 stat 的類型。傳回字串為:「file
」、「directory
」、「characterSpecial
」、「blockSpecial
」、「fifo
」、「link
」、「socket
」或「unknown
」。
File.stat("/dev/tty").ftype #=> "characterSpecial"
static VALUE rb_stat_ftype(VALUE obj) { return rb_file_ftype(get_stat(obj)); }
傳回 stat 擁有者的數字群組 ID。
File.stat("testfile").gid #=> 500
static VALUE rb_stat_gid(VALUE self) { return GIDT2NUM(get_stat(self)->st_gid); }
如果程序的有效群組 ID 與 stat 的群組 ID 相同,則傳回 true。在 Windows 上,傳回 false
。
File.stat("testfile").grpowned? #=> true File.stat("/etc/passwd").grpowned? #=> false
static VALUE rb_stat_grpowned(VALUE obj) { #ifndef _WIN32 if (rb_group_member(get_stat(obj)->st_gid)) return Qtrue; #endif return Qfalse; }
傳回 stat 的 inode 號碼。
File.stat("testfile").ino #=> 1083669
static VALUE rb_stat_ino(VALUE self) { #ifdef HAVE_STRUCT_STAT_ST_INOHIGH /* assume INTEGER_PACK_LSWORD_FIRST and st_inohigh is just next of st_ino */ return rb_integer_unpack(&get_stat(self)->st_ino, 2, SIZEOF_STRUCT_STAT_ST_INO, 0, INTEGER_PACK_LSWORD_FIRST|INTEGER_PACK_NATIVE_BYTE_ORDER| INTEGER_PACK_2COMP); #elif SIZEOF_STRUCT_STAT_ST_INO > SIZEOF_LONG return ULL2NUM(get_stat(self)->st_ino); #else return ULONG2NUM(get_stat(self)->st_ino); #endif }
產生 stat 的格式化描述。
File.stat("/etc/passwd").inspect #=> "#<File::Stat dev=0xe000005, ino=1078078, mode=0100644, # nlink=1, uid=0, gid=0, rdev=0x0, size=1374, blksize=4096, # blocks=8, atime=Wed Dec 10 10:16:12 CST 2003, # mtime=Fri Sep 12 15:41:41 CDT 2003, # ctime=Mon Oct 27 11:20:27 CST 2003, # birthtime=Mon Aug 04 08:13:49 CDT 2003>"
static VALUE rb_stat_inspect(VALUE self) { VALUE str; size_t i; static const struct { const char *name; VALUE (*func)(VALUE); } member[] = { {"dev", rb_stat_dev}, {"ino", rb_stat_ino}, {"mode", rb_stat_mode}, {"nlink", rb_stat_nlink}, {"uid", rb_stat_uid}, {"gid", rb_stat_gid}, {"rdev", rb_stat_rdev}, {"size", rb_stat_size}, {"blksize", rb_stat_blksize}, {"blocks", rb_stat_blocks}, {"atime", rb_stat_atime}, {"mtime", rb_stat_mtime}, {"ctime", rb_stat_ctime}, #if defined(HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC) {"birthtime", rb_stat_birthtime}, #endif }; struct rb_stat* rb_st; TypedData_Get_Struct(self, struct rb_stat, &stat_data_type, rb_st); if (!rb_st->initialized) { return rb_sprintf("#<%s: uninitialized>", rb_obj_classname(self)); } str = rb_str_buf_new2("#<"); rb_str_buf_cat2(str, rb_obj_classname(self)); rb_str_buf_cat2(str, " "); for (i = 0; i < sizeof(member)/sizeof(member[0]); i++) { VALUE v; if (i > 0) { rb_str_buf_cat2(str, ", "); } rb_str_buf_cat2(str, member[i].name); rb_str_buf_cat2(str, "="); v = (*member[i].func)(self); if (i == 2) { /* mode */ rb_str_catf(str, "0%lo", (unsigned long)NUM2ULONG(v)); } else if (i == 0 || i == 6) { /* dev/rdev */ rb_str_catf(str, "0x%"PRI_DEVT_PREFIX"x", NUM2DEVT(v)); } else { rb_str_append(str, rb_inspect(v)); } } rb_str_buf_cat2(str, ">"); return str; }
傳回代表 stat 權限位元的整數。位元的意義取決於平台;在 Unix 系統上,請參閱 stat(2)
。
File.chmod(0644, "testfile") #=> 1 s = File.stat("testfile") sprintf("%o", s.mode) #=> "100644"
static VALUE rb_stat_mode(VALUE self) { return UINT2NUM(ST2UINT(get_stat(self)->st_mode)); }
傳回 stat 的修改時間。
File.stat("testfile").mtime #=> Wed Apr 09 08:53:14 CDT 2003
static VALUE rb_stat_mtime(VALUE self) { return stat_mtime(get_stat(self)); }
傳回 stat 的硬連結數目。
File.stat("testfile").nlink #=> 1 File.link("testfile", "testfile.bak") #=> 0 File.stat("testfile").nlink #=> 2
static VALUE rb_stat_nlink(VALUE self) { /* struct stat::st_nlink is nlink_t in POSIX. Not the case for Windows. */ const struct stat *ptr = get_stat(self); if (sizeof(ptr->st_nlink) <= sizeof(int)) { return UINT2NUM((unsigned)ptr->st_nlink); } else if (sizeof(ptr->st_nlink) == sizeof(long)) { return ULONG2NUM((unsigned long)ptr->st_nlink); } else if (sizeof(ptr->st_nlink) == sizeof(LONG_LONG)) { return ULL2NUM((unsigned LONG_LONG)ptr->st_nlink); } else { rb_bug(":FIXME: don't know what to do"); } }
如果程序的有效使用者 ID 與 stat 的擁有者相同,則傳回 true
。
File.stat("testfile").owned? #=> true File.stat("/etc/passwd").owned? #=> false
static VALUE rb_stat_owned(VALUE obj) { if (get_stat(obj)->st_uid == geteuid()) return Qtrue; return Qfalse; }
如果作業系統支援管線且 stat 是管線,則傳回 true
;否則傳回 false
。
static VALUE rb_stat_p(VALUE obj) { #ifdef S_IFIFO if (S_ISFIFO(get_stat(obj)->st_mode)) return Qtrue; #endif return Qfalse; }
傳回代表 stat 所在裝置類型的整數。如果作業系統不支援此功能,則傳回 nil
。
File.stat("/dev/fd1").rdev #=> 513 File.stat("/dev/tty").rdev #=> 1280
static VALUE rb_stat_rdev(VALUE self) { #ifdef HAVE_STRUCT_STAT_ST_RDEV # if SIZEOF_STRUCT_STAT_ST_RDEV <= SIZEOF_DEV_T return DEVT2NUM(get_stat(self)->st_rdev); # elif SIZEOF_STRUCT_STAT_ST_RDEV <= SIZEOF_LONG return ULONG2NUM(get_stat(self)->st_rdev); # else return ULL2NUM(get_stat(self)->st_rdev); # endif #else return Qnil; #endif }
傳回 File_Stat#rdev
或 nil
的主要部分。
File.stat("/dev/fd1").rdev_major #=> 2 File.stat("/dev/tty").rdev_major #=> 5
static VALUE rb_stat_rdev_major(VALUE self) { #if defined(HAVE_STRUCT_STAT_ST_RDEV) && defined(major) return UINT2NUM(major(get_stat(self)->st_rdev)); #else return Qnil; #endif }
傳回 File_Stat#rdev
的次要部分或 nil
。
File.stat("/dev/fd1").rdev_minor #=> 1 File.stat("/dev/tty").rdev_minor #=> 0
static VALUE rb_stat_rdev_minor(VALUE self) { #if defined(HAVE_STRUCT_STAT_ST_RDEV) && defined(minor) return UINT2NUM(minor(get_stat(self)->st_rdev)); #else return Qnil; #endif }
如果此程序的有效使用者 ID 可讀取 stat,則傳回 true
。
File.stat("testfile").readable? #=> true
static VALUE rb_stat_r(VALUE obj) { struct stat *st = get_stat(obj); #ifdef USE_GETEUID if (geteuid() == 0) return Qtrue; #endif #ifdef S_IRUSR if (rb_stat_owned(obj)) return RBOOL(st->st_mode & S_IRUSR); #endif #ifdef S_IRGRP if (rb_stat_grpowned(obj)) return RBOOL(st->st_mode & S_IRGRP); #endif #ifdef S_IROTH if (!(st->st_mode & S_IROTH)) return Qfalse; #endif return Qtrue; }
如果此程序的實際使用者 ID 可讀取 stat,則傳回 true
。
File.stat("testfile").readable_real? #=> true
static VALUE rb_stat_R(VALUE obj) { struct stat *st = get_stat(obj); #ifdef USE_GETEUID if (getuid() == 0) return Qtrue; #endif #ifdef S_IRUSR if (rb_stat_rowned(obj)) return RBOOL(st->st_mode & S_IRUSR); #endif #ifdef S_IRGRP if (rb_group_member(get_stat(obj)->st_gid)) return RBOOL(st->st_mode & S_IRGRP); #endif #ifdef S_IROTH if (!(st->st_mode & S_IROTH)) return Qfalse; #endif return Qtrue; }
如果 stat 設定了 set-group-id 權限位元,則傳回 true
;如果未設定或作業系統不支援此功能,則傳回 false
。
File.stat("/usr/sbin/lpc").setgid? #=> true
static VALUE rb_stat_sgid(VALUE obj) { #ifdef S_ISGID if (get_stat(obj)->st_mode & S_ISGID) return Qtrue; #endif return Qfalse; }
如果 stat 設定了 set-user-id 權限位元,則傳回 true
;如果未設定或作業系統不支援此功能,則傳回 false
。
File.stat("/bin/su").setuid? #=> true
static VALUE rb_stat_suid(VALUE obj) { #ifdef S_ISUID if (get_stat(obj)->st_mode & S_ISUID) return Qtrue; #endif return Qfalse; }
傳回 stat 的大小(以位元組為單位)。
File.stat("testfile").size #=> 66
static VALUE rb_stat_size(VALUE self) { return OFFT2NUM(get_stat(self)->st_size); }
如果 stat 是零長度檔案,則傳回 nil
;否則傳回檔案的大小。
File.stat("testfile").size? #=> 66 File.stat(File::NULL).size? #=> nil
static VALUE rb_stat_s(VALUE obj) { rb_off_t size = get_stat(obj)->st_size; if (size == 0) return Qnil; return OFFT2NUM(size); }
如果 stat 是 socket,則傳回 true
;如果未設定或作業系統不支援此功能,則傳回 false
。
File.stat("testfile").socket? #=> false
static VALUE rb_stat_S(VALUE obj) { #ifdef S_ISSOCK if (S_ISSOCK(get_stat(obj)->st_mode)) return Qtrue; #endif return Qfalse; }
如果 stat 設定了 sticky 位元,則傳回 true
;如果未設定或作業系統不支援此功能,則傳回 false
。
File.stat("testfile").sticky? #=> false
static VALUE rb_stat_sticky(VALUE obj) { #ifdef S_ISVTX if (get_stat(obj)->st_mode & S_ISVTX) return Qtrue; #endif return Qfalse; }
如果 stat 是符號連結,則傳回 true
;如果未設定或作業系統不支援此功能,則傳回 false
。由於 File::stat
會自動追蹤符號連結,因此 symlink?
對於 File::stat
傳回的物件永遠會是 false
。
File.symlink("testfile", "alink") #=> 0 File.stat("alink").symlink? #=> false File.lstat("alink").symlink? #=> true
static VALUE rb_stat_l(VALUE obj) { #ifdef S_ISLNK if (S_ISLNK(get_stat(obj)->st_mode)) return Qtrue; #endif return Qfalse; }
傳回 stat 的擁有者的數字使用者 ID。
File.stat("testfile").uid #=> 501
static VALUE rb_stat_uid(VALUE self) { return UIDT2NUM(get_stat(self)->st_uid); }
如果 stat 可被其他人讀取,傳回表示 stat 的檔案權限位元的整數。否則傳回 nil
。位元的意義取決於平台;在 Unix 系統上,請參閱 stat(2)
。
m = File.stat("/etc/passwd").world_readable? #=> 420 sprintf("%o", m) #=> "644"
static VALUE rb_stat_wr(VALUE obj) { #ifdef S_IROTH struct stat *st = get_stat(obj); if ((st->st_mode & (S_IROTH)) == S_IROTH) { return UINT2NUM(st->st_mode & (S_IRUGO|S_IWUGO|S_IXUGO)); } #endif return Qnil; }
如果 stat 可被其他人寫入,傳回表示 stat 的檔案權限位元的整數。否則傳回 nil
。位元的意義取決於平台;在 Unix 系統上,請參閱 stat(2)
。
m = File.stat("/tmp").world_writable? #=> 511 sprintf("%o", m) #=> "777"
static VALUE rb_stat_ww(VALUE obj) { #ifdef S_IWOTH struct stat *st = get_stat(obj); if ((st->st_mode & (S_IWOTH)) == S_IWOTH) { return UINT2NUM(st->st_mode & (S_IRUGO|S_IWUGO|S_IXUGO)); } #endif return Qnil; }
如果 stat 可被此程序的有效使用者 ID 寫入,傳回 true
。
File.stat("testfile").writable? #=> true
static VALUE rb_stat_w(VALUE obj) { struct stat *st = get_stat(obj); #ifdef USE_GETEUID if (geteuid() == 0) return Qtrue; #endif #ifdef S_IWUSR if (rb_stat_owned(obj)) return RBOOL(st->st_mode & S_IWUSR); #endif #ifdef S_IWGRP if (rb_stat_grpowned(obj)) return RBOOL(st->st_mode & S_IWGRP); #endif #ifdef S_IWOTH if (!(st->st_mode & S_IWOTH)) return Qfalse; #endif return Qtrue; }
如果 stat 可被此程序的實際使用者 ID 寫入,傳回 true
。
File.stat("testfile").writable_real? #=> true
static VALUE rb_stat_W(VALUE obj) { struct stat *st = get_stat(obj); #ifdef USE_GETEUID if (getuid() == 0) return Qtrue; #endif #ifdef S_IWUSR if (rb_stat_rowned(obj)) return RBOOL(st->st_mode & S_IWUSR); #endif #ifdef S_IWGRP if (rb_group_member(get_stat(obj)->st_gid)) return RBOOL(st->st_mode & S_IWGRP); #endif #ifdef S_IWOTH if (!(st->st_mode & S_IWOTH)) return Qfalse; #endif return Qtrue; }
如果 stat 是零長度檔案,傳回 true
;否則傳回 false
。
File.stat("testfile").zero? #=> false
static VALUE rb_stat_z(VALUE obj) { if (get_stat(obj)->st_size == 0) return Qtrue; return Qfalse; }