Tạo thư mục nếu nó không tồn tại với Ruby


156

Tôi đang cố gắng tạo một thư mục với đoạn mã sau:

Dir.mkdir("/Users/Luigi/Desktop/Survey_Final/Archived/Survey/test")
    unless File.exists?("/Users/Luigi/Desktop/Survey_Final/Archived/Survey/test")  

Tuy nhiên, tôi đang nhận được lỗi này:

Không có tệp hoặc thư mục như vậy - / Users / Luigi / Desktop / Survey_Final / Archured / Survey / test (Errno :: ENOENT)

Tại sao thư mục này không được tạo bởi Dir.mkdirtuyên bố trên?


4
File.exists?()hoạt động trên các tập tin và thư mục. Nó không biết sự khác biệt.
Tin Man

Câu trả lời:


263

Bạn có thể đang cố gắng tạo các thư mục lồng nhau. Giả sử fookhông tồn tại, bạn sẽ nhận được no such file or directorylỗi cho:

Dir.mkdir 'foo/bar'
# => Errno::ENOENT: No such file or directory - 'foo/bar'

Để tạo các thư mục lồng nhau cùng một lúc, FileUtilslà cần thiết:

require 'fileutils'
FileUtils.mkdir_p 'foo/bar'
# => ["foo/bar"]

Edit2: bạn không phải sử dụng FileUtils, bạn có thể thực hiện cuộc gọi hệ thống (cập nhật từ @mu là nhận xét quá ngắn):

> system 'mkdir', '-p', 'foo/bar' # worse version: system 'mkdir -p "foo/bar"'
=> true

Nhưng dường như (ít nhất là đối với tôi) là cách tiếp cận tồi tệ hơn khi bạn đang sử dụng 'công cụ' bên ngoài có thể không khả dụng trên một số hệ thống (mặc dù tôi khó có thể tưởng tượng hệ thống mà không có mkdir, nhưng ai biết được).


5
system 'mkdir', '-p', 'foo/bar'sẽ là một phiên bản tốt hơn của systemcuộc gọi đó . Không cần quá trình shell bổ sung hoặc trích dẫn / thoát / tiêm vô nghĩa thông thường đi kèm với phiên bản đối số duy nhất của system.
mu quá ngắn

6
systemsẽ khởi chạy /bin/shđể phân tích mkdir -p "foo/bar"chuỗi và sau đó shell sẽ chạy /bin/mkdir. Vì vậy, bạn đang làm thêm (tạo chuỗi lệnh, khởi chạy /bin/shđể kéo nó ra một lần nữa) và một số công việc phụ đó khiến bạn mở các cuộc tấn công shell shell (dành một chút thời gian trong các lời khuyên của CERT cho Ruby và bạn sẽ thấy mức độ phổ biến vấn đề này là).
mu quá ngắn

1
@muistooshort @ zrl3dx làm thế nào để một systemcuộc gọi tốt hơn fileutilsmột lần nữa? Tôi đang ở trên Windows và mkdir_phoạt động rất tốt mà không sinh ra một mạng con chỉ để phân tích mkdir -pcái mà sẽ thất bại. Vui mừng đó fileutilslà sự thay thế đầu tiên trong câu trả lời.
TWiStErRob

1
@TWiStErRob: Đọc lại bình luận của tôi, tôi không nói gì về fileutilshoặc mkdir_ptất cả những gì tôi nói system command, arg1, arg2, ...là tốt hơn thế system command_with_arguments.
mu quá ngắn

3
@muistooshort ah, xin lỗi, vì vậy bạn chỉ nói rằng có một cách tốt hơn để thực hiện tùy chọn xấu :)
TWiStErRob

71

Cách đơn giản:

directory_name = "name"
Dir.mkdir(directory_name) unless File.exists?(directory_name)

8
Người ta sẽ sử dụng File.directory? thay vì File.exists?
Florin Asăvoaie

4
Giả sử có một tệp bình thường có cùng tên. Bạn không thể tạo một thư mục trong trường hợp đó.
Mikołaj Rozwadowski

3
Nó cũng tạo ra một điều kiện chủng tộc. Các tập tin có thể được tạo ra sau khi kiểm tra nhưng trước khi tạo.
Don Reba

25

Một cách đơn giản khác:

Dir.mkdir('tmp/excel') unless Dir.exist?('tmp/excel')


Nếu bạn muốn tạo các thư mục lồng nhau thì điều này không hoạt động. Ví dụ, tôi muốn tạo thư mục sau /home/jignesh/reports/testnhưng sử dụng giải pháp này RUBY (Errno::ENOENT), no such file or directory @ dir_s_mkdir. Vì vậy, giải pháp đáng tin cậy đang sử dụngFileUtils.mkdir_p
Jignesh Gohel

-5

Thế còn Dir.mkdir('dir') rescue nil?


3
Tránh sử dụng rescueở dạng sửa đổi của nó.
Sebastian Palma

1
Quan tâm giải thích tại sao tôi nên viết 5 dòng mã thay vì chỉ 1? Tôi muốn thấy bạn thử.
Vidar


1
Tôi đã làm rồi, và tôi hoàn toàn không đồng ý, tôi nghĩ điều đó thật ngớ ngẩn, vậy có lẽ bạn có thể khai sáng cho tôi?
Vidar

6
Điều này sẽ bắt được bất kỳ ngoại lệ nào không phải là điều bạn đang cố gắng thực hiện và trong một ứng dụng trong thế giới thực sẽ che giấu các vấn đề khiến việc bảo trì khó khăn hơn. Ngoài ra, không nên sử dụng ngoại lệ làm điều kiện, theo nghĩa phần cứng, chúng chạy chậm hơn nhiều (có thể không thực sự là vấn đề trong ngôn ngữ hiện đại nhưng vẫn khiến bạn trông thiếu kinh nghiệm như một lập trình viên).
Ed_
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.