-
Notifications
You must be signed in to change notification settings - Fork 4.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[API Proposal]: Creating an empty temporary directory #72881
Comments
Tagging subscribers to this area: @dotnet/area-system-io Issue DetailsBackground and motivationWhen dealing with temporary files, especially with more than one, we would like to create our own folder and place them inside. There are several ways to achieve this but for convenience and for completion of the existing Path.GetTempFileName there should be an official API for this. This has been requested a few times before (#2048, #23538, #31243). #2048 is a large higher-level API proposal for an object model of working with temporary files. To make forward progress here, for 7.0 we should add a simple API that creates a new, empty temp directory. This would correspond with other Unix POSIX work we've been doing in 7.0 (#68770, #67837). On Unix, this would use API Proposalnamespace System.IO;
public static class Path
{
public static string GetTempPath();
public static string GetTempFileName();
+ /// <summary>
+ /// Creates a uniquely named, empty directory on disk and returns the full path of that directory.
+ /// </summary>
+ public static string GetTempDirectoryName();
} API Usagestring tempDirectory = Path.GetTempDirectoryName();
File.WriteAllText(Path.Combine(tempDirectory, "file1.txt"), "First file");
File.WriteAllText(Path.Combine(tempDirectory, "file2.txt"), "Second file");
// do something with file1.txt and file2.txt
Directory.Delete(tempDirectory, recursive: true); Alternative DesignsAlternatively we could create a full blown TemporaryDirectory class as proposed in #2048. However, that API can be built on top of this one in the future. Adding this lower-level API separately allows for new code to start using it now. RisksNo response
|
This comment was marked as off-topic.
This comment was marked as off-topic.
I wonder if the similarity between |
I guess you can use Path.GetRandomFileName() rather than a GUID. |
I went back and forth on using Create, or being consistent with GetTempFileName. I think your comment pushed me to be fully behind using Create in the name. It is just the better name, even if it is inconsistent with GetTempFileName.
It would be shorter - GUIDs are 32 characters long, GetRandomFileName is 12 (8 + One other question that has come up is: should this return a Another alternative is we could put it on |
Linux especially (unsure about Windows) the default temp directory is a |
If we use a Guid, I think NewGuid is a wrong option. NewGuid tries to generate a cryptographically secure random Guid. I created several times ago a proposal for creating a Non cryptographical Guid for ex. #65736. |
On my windows machine, I'm not seeing much of a performance difference in the following benchmark between doing [MemoryDiagnoser]
public class CreateTemporaryDirectoryBenchmark
{
[Benchmark]
public void CreateTemporaryDirectory()
{
var path = Path.CreateTemporaryDirectory();
Directory.Delete(path);
}
}
The extra allocation is due to Guid being 32 characters vs random file name being only 12. You can see the implementation difference between these two in: 028637e |
namespace System.IO;
public static class Path
{
// Existing:
// public static string GetTempPath();
// public static string GetTempFileName();
[EditorBrowsable(EditorBrowsableState.Never)]
public static string GetTempFileName();
}
public partial class File
{
public static FileInfo CreateTempFile(string? prefix = null, string? suffix = null);
}
public partial class Directory
{
public static DirectoryInfo CreateTempSubdirectory(string? prefix = null);
} |
In python temp files/directories are context objects, you can do the equivalent of: using(var tmp = File.CreateAndOpenTempFile(FileMode.Create))
{
DoSomething(tmp);
} ... and the objects are automatically cleaned up afterwards. Of course, doing that also auto-opens the file as well... Should something like this be considered? Or this is just the base functionality, and that's a feature that should maybe be considered later. |
See the linked issue above - #2048 |
I have few questions regarding: public partial class File
{
public static FileInfo CreateTempFile(string? prefix = null, string? suffix = null);
} I wonder what the typical scenario is going to be: just creating the file or creating and using it right away. If the latter, we could make it more performant by returning Also, is our goal to create a file in temporary directory or a temporary file that disappears after being closed? We could use O_TMPFILE and FILE_ATTRIBUTE_TEMPORARY to implement it. |
Part of the problem here is that it depends on the APIs the caller needs to use. |
There are many places that call Given this feedback/questions, and in trying to lock down for .NET 7, I am just going to implement the Directory API above that was approved. We can iterate on the file API in a future version when we have more time to ensure we are getting it right.
I think that might be a good option to add in the future. But I don't think that is the only use case. Looking at how people use the GetTempFileName API, there are places that use the file in multiple processes. Here's one in |
CreateTempSubdirectory will create a new uniquely named directory under the temp directory. This allows applications to write temporary files in a co-located directory. Contributes to dotnet#72881
What is the use case for why an empty file should be created by the Name collisions would not be a problem if the name contains a Guid. It is not necessary to take precautions against collisions. A name collision is like winning the lottery 10 times in a row (according to some quick math: 1 to 1 million vs. 1 to 2^128). |
The same use cases for the existing
The name is not guaranteed to contain a Guid. |
Also a GUID can collide even if it is only every 340_282_366_920_938_463_463_374_607_431_768_211_455th case. |
* Add Directory.CreateTempSubdirectory CreateTempSubdirectory will create a new uniquely named directory under the temp directory. This allows applications to write temporary files in a co-located directory. Contributes to #72881
Hmm, what is the difference between Directory.CreateDirectory()? #2048 is exactly what we need. |
To create a directory with a unique name and assign a 700 mask, you don't need a new API at all - everything is already there. This has probably been discussed a couple of times before and was the reason for the rejection. What is not addressed in any way is the actual use cases of temporary entities, where developers have to keep track of garbage removal, while an API can do it automatically. |
@iSazonov how would you do it then? Directory.CreateDirectory(String, UnixFileMode) lets you specify the 700 mode for a new directory but it doesn't tell you whether a directory at the specified path existed already, so you won't know whether you need to generate a new name and retry. |
What do you do now if this API doesn't exist? 😺 I can assume that you are not going to invent something complicated and just use new guid as a name. |
I used Platform Invoke actually. |
is this a candidate for labeling 'help wanted'-- perhaps someone here is interested. |
This issue covered three approved APIs: Path.GetTempFileName();
File.CreateTempFile(string? prefix = null, string? suffix = null);
Directory.CreateTempSubdirectory(string? prefix = null); The first and third were implemented, and there seem to be a bunch of questions about the usefulness of the second, or whether it's the correct shape. @eerhardt, do we still want to add the second method? Should this issue instead be closed? Or do we want to move it back to api-needs-work for revisions to the second? |
Only the third was implemented. The first change was to add I think we should still consider the second method: |
Background and motivation
When dealing with temporary files, especially with more than one, we would like to create our own folder and place them inside. There are several ways to achieve this but for convenience and for completion of the existing Path.GetTempFileName there should be an official API for this.
This has been requested a few times before (#2048, #23538, #31243). #2048 is a large higher-level API proposal for an object model of working with temporary files. To make forward progress here, for 7.0 we should add a simple API that creates a new, empty temp directory. This would correspond with other Unix POSIX work we've been doing in 7.0 (#68770, #67837).
On Unix, this would use
mkdtemp
, just like how Path.GetTempFileName usesmkstemps
. On Windows, this API would generate a new random directory name (possibly using Guid.NewGuid) guaranteeing that the new directory was freshly created.API Proposal
API Usage
Open Questions
Should CreateTemporaryDirectory optionally take a
string prefix
?mkdtemp
allows for prefixes. It would allow for libraries/components to "group" their temp directories together in case users need to find them for some reason.Should it return
DirectoryInfo
instead ofstring
? No other methods inPath
deal withFileInfo
andDirectoryInfo
.We could put it on
Directory.CreateTemporaryDirectory()
instead ofPath
- butPath
is whereGetTempPath
andGetTempFileName
is. It would be hard to justify putting it in a separate class from the rest of the "temp" methods.Alternative Designs
Alternatively we could create a full blown TemporaryDirectory class as proposed in #2048. However, that API can be built on top of this one in the future. Adding this lower-level API separately allows for new code to start using it now.
Risks
No response
The text was updated successfully, but these errors were encountered: