-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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]: DirectoryInfo.Copy / Directory.Copy #60903
Comments
Tagging subscribers to this area: @dotnet/area-system-io Issue DetailsBackground and motivationThe purpose is to copy the entire directory to a new place, optionally recursive. Currently the only way is to create the target directory first, then enumerate all files in the source directory and copy them one by one. While we already have In terms for exception handling it could be the same as for the existing API Proposalnamespace System.IO
{
public sealed class DirectoryInfo : FileSystemInfo
{
public void Copy(string destDirName);
public void Copy(string destDirName, bool recursive);
}
} API Usage//OLD behavior
foreach (string dir in Directory.GetDirectories("F:\\Folder", "*", SearchOption.AllDirectories))
{
Directory.CreateDirectory(dir.Replace("F:\\Folder", "F:\\newFolder"));
}
foreach (string file in Directory.GetFiles("F:\\Folder", "*.*",SearchOption.AllDirectories))
{
File.Copy(file, file.Replace("F:\\Folder", "F:\\newFolder"), true);
}
//New behavior
DirectoryInfo di = new("F:\\Folder");
di.Copy("F:\\newFolder", true); Alternative DesignsAlternatively it could (also?) be part of namespace System.IO
{
public static class Directory
{
public void Copy(string sourceDirName, string destDirName);
public void Copy(string sourceDirName, string destDirName, bool recursive);
}
} Something else to think about is if we add a third overload to optionally overwrite existing files. While this is useful only namespace System.IO
{
public static class Directory
{
public void Copy(string sourceDirName, string destDirName, bool recursive, bool overwriteExistingFiles);
}
public sealed class DirectoryInfo : FileSystemInfo
{
public void Copy(string destDirName, bool recursive, bool overwriteExistingFiles);
}
} RisksNo response
|
Does seem OK, but I would definitely also go for both the alternative design and the original design. I think it would be weird for us to only implement this inside |
Getting some kind of status updates during copy operations would also be nice.
|
Yes I absolutely agree, but you don't get these from existing |
Move is very different behavior to copy. Move is just a rename which is why it throws if you try and move to a different volume, so it can't emit any of this data because its a single atomic operation. It would be really handy to have a built-in copy function but it needs to be carefully thought out. |
That's interesting, didn't know that. On Windows if it fails on one file in the middle, the whole copy operation fails (in some cases you can skip the failing file but not in all). I would have expect something similar from .NET api. copying files one by one and simply throws if it fails on one file. Running out of space is something the developer can check himself first. For any other IO issue it can just throw. Developer can catch, handle and re-try if necessary. This is clearly not THE BEST behavior but in order to make it the best behavior there is a lot of other stuff to do like @batzen suggested. If you look at the high voted solutions from Stackoverflow its also just file copy one by one. If it fails somewhere the whole operation fails. There is no deeper logic in here for now and it still makes many devs happy enough. You can also look at the recommended solution on MSDN or look into the VB API, its the same. So if three different sources are behaving the same then I would suggest to do the same. Highest chance this API gets approved. If we lose ourselves in questioning how we can handle each edge scenario, API will likely get denied because of being too complex and too different to any existing IO api. My proposal is to have an inbuilt solution for something simple and useful like that, not relying to Stackoverflow/VB or MDSN. It can easily be the same/similar implementation. |
The operation fails, but does it roll back the files already copied? If not, now you have to figure out the resulting state.
Nope (or at least, that's not sufficient). There's multiple reasons the available space can change in the middle of the copy operation (and by that I mean during the file byte copy). That aside, I'm assuming that, like pretty much the rest of the IO stack we're going to be wrapping some OS function here, so capabilities may be dictated by what the various OS flavors provide. |
Does it also make sense to provide these new Copy methods as async aswell? (But this would also apply to File.Copy) |
Another likely complication, or at least something where a decision had to be made:
|
Simply follow the behavior of File.Copy. If the current behavior is not what you believe it should be than make another issue. |
that space issue can be avoided by first obtaining the size of each file that needs to be copied and then using the new .NET 6 file apis to reserve that space so that way the copy operation won't fail. There is also another added benefit of doing that as well, you can then throw if the reservation of space for a specific file fails and be able to tell them for which file it happened on in the exception message. |
Agree. The proposal makes sense, I would just add the |
namespace System.IO
{
public partial class DirectoryInfo : FileSystemInfo
{
public bool CopyTo(string destinationPath, bool recursive);
public bool CopyTo(string destinationPath, bool recursive, bool skipExistingFiles=true, CancellationToken cancellationToken=default);
}
public partial class Directory
{
public static bool Copy(string sourcePath, string destinationPath, bool recursive);
public static bool Copy(string sourcePath, string destinationPath, bool recursive, bool skipExistingFiles=true, CancellationToken cancellationToken=default);
}
} |
@deeprobin Did you gave up? No response on your PR for 6 days. |
No, they just need to work everything out with reviews first. |
I have not given up. However, I also have other PRs to work on apart from this one still needs clarification, as @AranHaan already said.
If I have the time, I will of course add the ref-assembly implementation, doc-comments and tests. |
Consider using an I wonder why someone would not want a recursive copy. Is this needed at all? What does the overload |
More feedback came up on the implementing PR. We need to reach consensus on the error policy before adding this API.
|
We could consider follow https://en.cppreference.com/w/cpp/filesystem/copy as good start point. |
Why not considering the VB.NET implementation instead? It already has a .NET runtime implementation which can be taken and improved where it needs. It also handles errors which way we can change if necessary. And it's been one of the recommended solutions of "How can I do this in C#" 🤷♂️ I mean of course we can take a completely different language implementation as a reference point. Completely starting the .NET implementation from scratch. Making it much more complex than necessary with callbacks. Its just that... why making it more difficult than necessary? For me the VB.NET implementation is pretty much perfect because:
The only thing I would probably change is that it not only returns the last exception but all exceptions, so I could see for example all the files which have failed if necessary. |
Can you add a reference on the implementation? |
Internal implementation: Here it copy the files one by one and continues on errors (but saving the exception): |
@Symbai Thanks for additional information! Looking VB implementation I think it is too "naive" and does not meet the requirements of the .Net C# community at all. |
Can you be more specific? And did you by chance misread my previous comment where I wrote |
What's the status on this? The proposal has been approved but the PR has been rejected, because the implementation wasn't good enough. What's next? Does this need to be reviewed again because in the review process you guys and girls are discussing how it should get implemented? If so, could someone please re-add the "ready-for-review" label? If not, what needs to be done? |
Let me summarize:
I'm at the point now where I think we should reject this feature and let people do their own recursive walk because that means they have full control over the policy because offering an API with a configurable policy seems more complicated. |
@terrajobst for ex. |
This isn't the first time I've been confused as to why having |
Is the set of possible configuration options really that large? I'd say that the following (configured as an enum) would cover 99% of the use cases.
I'd say that the settings "recursive, no overwrite, no continue on error" are already the 95% use case. Most programmatic copies are really simple... Just duplicate a plain directory without any complications. Programmatic copies tend to be much simpler than what a user would want to do in a GUI such as Windows Explorer. As suggested above, symbolic links would simply match the This feature does not have to be a swiss army knife. If a user wants that they have to do it themselves. In my view, it is a long-standing missing feature that .NET cannot... copy a directory. This seems like a highly desirable thing to have. I certainly have needed it. Downsides of writing a custom copy algorithm:
Can we at least keep this issue open as a tracking issue? Closing it would be a strong signal for future visitors that the very concept has been rejected. It seems that, at this time, the team is merely not seeing a good path to do it but they do not reject the idea outright. |
Maybe? Or the ability to provide a filter func. |
Any update so far? |
No. According to stephentoub this proposal needs someone from the .NET runtime team, who really cares about it, to push it forward, see his comment #74273 (comment) but I cannot explain you why. |
Background and motivation
The purpose is to copy the entire directory to a new place, optionally recursive. Currently the only way is to create the target directory first, then enumerate all files in the source directory and copy them one by one. While we already have
DirectoryInfo.MoveTo()
andDirectoryInfo.Delete()
many developers are looking forward forDirectoryInfo.Copy
as well, see high voted https://stackoverflow.com/questions/58744/copy-the-entire-contents-of-a-directory-in-c-sharpIn terms for exception handling it could be the same as for the existing
Move
orFile.Copy
methods. There is a further discussion here on improving the exception handling but I believe this should be tracked and discussed in another issue. This proposal is for closing the gap only.//Edit: 11/25/21, added
overwriteExistingFiles
overload to main proposal based on @jozkee feedback.API Proposal
API Usage
Alternative Designs
Alternatively it could (also?) be part of
System.IO.Directory
class, they also haveMove
andDelete
methods.Risks
No response
The text was updated successfully, but these errors were encountered: