1

Is there a way to rename created temp files in ruby.

    file = Tempfile.new("prefix", Dir.tmpdir, encoding: 'ascii-8bit')
    file.write(content)
    file.close
    file

#File:/var/XXX/mz/37g0z42324fffnqy_27h0000gn/T/prefix20210223-44327-1mn74mk

I want a temp file to renamed with the given name.This is to retain the original name of the file. I want the file to be short lived only so creating a normal file wont work in this case.

But I tried FileUtils like this to see if copy works.

file = Tempfile.new("XXZZA", Dir.tmpdir, encoding: 'ascii-8bit')
=> #<File:/var/folders/mz/37g0zms52cg6bh0n5nqy_27h0000gn/T/XXZZA20210223-44327-10gvnou>
[78] pry(main)> file.write("Its a new text file")
=> 19
[79] pry(main)> nfile = File.join("public", "XXXXAAnew")
=> "public/XXXXAAnew"
[80] pry(main)> FileUtils.cp file.path, nfile
=> nil
[81] pry(main)> file.close
=> nil
[82] pry(main)> file
=> #<File:/var/folders/mz/37g0zms52cg6bh0n5nqy_27h0000gn/T/XXZZA20210223-44327-10gvnou (closed)>
[83] pry(main)> nfile
"public/XXXXAAnew"

but the file is empty

also, copied file is not cleaned up by garbage collector

user3636388
  • 187
  • 2
  • 24
  • What was in `new_file` and what was the error from `FileUtils.cp`? – Schwern Feb 23 '21 at 06:08
  • new_file has a file path. I tried this solution https://stackoverflow.com/questions/28539804/rails-rename-tempfile – user3636388 Feb 23 '21 at 06:15
  • What was the error, and what was the file path? And are you just trying to rename the file, or put it into a new directory? – Schwern Feb 23 '21 at 06:18
  • file = Tempfile.new("XXZZA", Dir.tmpdir, encoding: 'ascii-8bit') => # [78] pry(main)> file.write("Its a new text file") => 19 [79] pry(main)> nfile = File.join("public", "XXXXAAnew") => "public/XXXXAAnew" [80] pry(main)> FileUtils.cp file.path, nfile => nil [81] pry(main)> file.close => nil [82] pry(main)> file => # [83] pry(main)> nfile "public/XXXXAAnew" but the file is empty – user3636388 Feb 23 '21 at 06:24
  • You can rename a file using [`File#rename`](https://ruby-doc.org/core-3.0.0/File.html#method-c-rename) – user1934428 Feb 23 '21 at 07:57
  • using Tempfile. – user3636388 Feb 23 '21 at 08:00
  • Why don't you use a regular file? You can unlink it when you're done. – Stefan Feb 23 '21 at 12:21
  • yes that's what I have done now. – user3636388 Feb 23 '21 at 15:18

1 Answers1

1

but the file is empty

The copy worked, but the temp file was empty when you copied it. You are suffering from buffering.

Writing to disk is slow, so most programming languages will buffer your writes to memory. The buffer will be written to disk, "flushed", when it gets too large, or when the file is closed. file.write writes to the buffer, not to disk. The file is empty when you copy it.

To avoid this, flush the buffer to ensure all writes are committed to disk before copying.

file.write("Its a new text file")
file.flush
FileUtils.cp file.path, nfile

But if you're going to copy the file, why use a temp file at all? The copy is not a temp file.


Instead, you can control the prefix, extension, and directory of the Tempfile.

file = Tempfile.new(['prefix', '.ext'], "public", encoding: 'ascii-8bit')

That will create a tempfile in the directory public/ which begins with prefix and has .ext extension. Something like public/prefix20210222-50550-i81pw7r.ext.

Alternately, make a temp dir with Dir.mktmpdir and put the file in there.

require 'tmpdir'

Dir.mktmpdir do |dir|
  file = File.open(File.join(dir, "somefile"), "w")
  ...
end
Schwern
  • 153,029
  • 25
  • 195
  • 336
  • My usecase is to create a short lived temp file with given name(original name). I didn't find any way to do that. So I tried this way. – user3636388 Feb 23 '21 at 06:40
  • @user3636388 It doesn't rename the file, it copies it. The copy will not be cleaned up. – Schwern Feb 23 '21 at 06:45
  • Is there a way to rename the temp file – user3636388 Feb 23 '21 at 06:47
  • @user3636388 Not that I can see, which is a bummer, but you can control the directory and extension. I'll update the answer. – Schwern Feb 23 '21 at 06:50
  • I was thinking if creating a normal file inside tmpdir would help. – user3636388 Feb 23 '21 at 06:55
  • @user3636388 Depends on your purpose. Why do you need to rename the file? – Schwern Feb 23 '21 at 07:11
  • I'm sending the file to some system where it is integrated with PGP to be encrypted. PGP encrypts and uploads to another sys with the original file name from its metadata or whatever. In this way I can know which file has been encrypted. if it is temp file, it returns some unique timestamp and random numbers, finding it is difficult to understand which file – user3636388 Feb 23 '21 at 07:13
  • @user3636388 Can you specify a different name when you send the file? – Schwern Feb 23 '21 at 07:16
  • No we cannot. we can just send the encrypted file content – user3636388 Feb 23 '21 at 07:17
  • 1
    @user3636388 You could use [`Dir.mktmpdir`](https://ruby-doc.org/stdlib-2.7.2/libdoc/tmpdir/rdoc/Dir.html) and put the file in there. – Schwern Feb 23 '21 at 07:28