ここでは、エクスプローラなどに貼付けができるようにファイル(またはフォルダ)をコピーしたり、切り取り(カット)をする方法とを紹介します。また、エクスプローラなどでコピーやカットしたファイルのパスを取得する方法と、コピーやカットしたファイルを貼り付ける方法も紹介します。
まずは、指定したファイルをクリップボードにコピーする方法です。
.NET Framework 2.0からは、Clipboard.SetFileDropListメソッドを使って簡単にコピーすることができます。
'Imports System.Windows.Forms 'コピーするファイルのパスをStringCollectionに追加する Dim files As New System.Collections.Specialized.StringCollection() files.Add("C:\1.txt") files.Add("C:\2.txt") files.Add("C:\3.txt") 'クリップボードにコピーする Clipboard.SetFileDropList(files)
//using System.Windows.Forms; //コピーするファイルのパスをStringCollectionに追加する System.Collections.Specialized.StringCollection files = new System.Collections.Specialized.StringCollection(); files.Add("C:\\1.txt"); files.Add("C:\\2.txt"); files.Add("C:\\3.txt"); //クリップボードにコピーする Clipboard.SetFileDropList(files);
補足:VB.NETでは、My.Computer.Clipboard.SetFileDropListメソッドを使っても同じことができます。
.NET Framework 1.1以前では、Clipboard.SetDataObjectメソッドを使用し、DataFormats.FileDrop形式のDataObjectオブジェクトをクリップボードに貼り付けます。データはコピーするファイルのパスの配列にします。
'Imports System.Windows.Forms 'コピーするファイルのパス Dim fileNames As String() = {"C:\1.txt", "C:\2.txt", "C:\3.txt"} 'ファイルドロップ形式のDataObjectを作成する Dim data = New DataObject(DataFormats.FileDrop, fileNames) 'クリップボードにコピーする Clipboard.SetDataObject(data)
//using System.Windows.Forms; //コピーするファイルのパス string[] fileNames = {"C:\\1.txt", "C:\\2.txt", "C:\\3.txt"}; //ファイルドロップ形式のDataObjectを作成する IDataObject data = new DataObject(DataFormats.FileDrop, fileNames); //クリップボードにコピーする Clipboard.SetDataObject(data);
ファイルを切り取る方法は、コメントで教えていただきました。また、「IronInTheFire.Net - Clipboard File Operations」などでも紹介されています。これらを参考にして、以下のサンプルを書かせていただきました。
'Imports System.Windows.Forms '切り取るファイルのパス Dim fileNames As String() = {"C:\1.txt", "C:\2.txt", "C:\3.txt"} 'ファイルドロップ形式のDataObjectを作成する Dim data As IDataObject = New DataObject(DataFormats.FileDrop, fileNames) 'DragDropEffects.Moveを設定する(DragDropEffects.Move は 2) Dim bs As Byte() = New Byte() {CByte(DragDropEffects.Move), 0, 0, 0} Dim ms As System.IO.MemoryStream = New System.IO.MemoryStream(bs) data.SetData("Preferred DropEffect", ms) 'クリップボードに切り取る Clipboard.SetDataObject(data)
//using System.Windows.Forms; //切り取るファイルのパス string[] fileNames = { "C:\\1.txt", "C:\\2.txt", "C:\\3.txt" }; //ファイルドロップ形式のDataObjectを作成する IDataObject data = new DataObject(DataFormats.FileDrop, fileNames); //DragDropEffects.Moveを設定する(DragDropEffects.Move は 2) byte[] bs = new byte[] { (byte)DragDropEffects.Move, 0, 0, 0 }; System.IO.MemoryStream ms = new System.IO.MemoryStream(bs); data.SetData("Preferred DropEffect", ms); //クリップボードに切り取る Clipboard.SetDataObject(data);
.NET Framework 2.0以降では、Clipboard.GetFileDropListメソッドを使って簡単にコピーされたファイルのパスを取得できます。
'Imports System.Windows.Forms 'クリップボードにファイルドロップ形式のデータがあるか確認 If Clipboard.ContainsFileDropList() Then 'データを取得する(取得できなかった時はNothing) Dim files As System.Collections.Specialized.StringCollection = _ Clipboard.GetFileDropList() '取得したファイル名を列挙する Dim fileName As String For Each fileName In files Console.WriteLine(fileName) Next fileName End If
//using System.Windows.Forms; //クリップボードにファイルドロップ形式のデータがあるか確認 if (Clipboard.ContainsFileDropList()) { //データを取得する(取得できなかった時はnull) System.Collections.Specialized.StringCollection files = Clipboard.GetFileDropList(); //取得したファイル名を列挙する foreach (string fileName in files) { Console.WriteLine(fileName); } }
補足:VB.NETでは、My.Computer.Clipboard.GetFileDropListメソッドを使っても同じことができます。
「クリップボードに文字列をコピー、クリップボードから文字列を取得」で紹介しているのと同じように、Clipboardクラス(System.Windows.Forms名前空間)のGetDataObjectメソッドを使うことにより、コピーされたファイルのパスを取得できます。IDataObject.GetDataメソッドでデータを抽出する際にはDataFormats.FileDropデータ形式を指定し、文字列配列として取得します。
次のコードでは、クリップボードにファイルがコピーされている時にそのパスを取得し、出力しています。
'Imports System.Windows.Forms 'クリップボードのデータを取得する Dim data As IDataObject = Clipboard.GetDataObject() 'クリップボードにファイルドロップ形式のデータがあるか確認 If data.GetDataPresent(DataFormats.FileDrop) Then 'データを取得する(取得できなかった時はNothing) Dim fileNames As String() = _ CType(data.GetData(DataFormats.FileDrop), String()) '取得したファイル名を列挙する Dim fileName As String For Each fileName In fileNames Console.WriteLine(fileName) Next fileName End If
//using System.Windows.Forms; //クリップボードのデータを取得する IDataObject data = Clipboard.GetDataObject(); //クリップボードにファイルドロップ形式のデータがあるか確認 if (data.GetDataPresent(DataFormats.FileDrop)) { //データを取得する(取得できなかった時はnull) string[] fileNames = (string[]) data.GetData(DataFormats.FileDrop); //取得したファイル名を列挙する foreach (string fileName in fileNames) { Console.WriteLine(fileName); } }
エクスプローラ等でコピー、または切り取られたファイルを貼り付けるには、先に紹介した方法でコピーされたファイルのパスを取得し、そのファイルを「ファイルをコピー、移動(名前の変更)、削除する」で紹介しているような方法でコピー、または移動します。
ただここで問題になるのは、ファイルがコピーされたのか切り取られたのかをどうやって知るかということです。この方法についても「IronInTheFire.Net - Clipboard File Operations」などで説明されています。
ファイルを貼り付ける簡単なコード(PasteFilesメソッド)を書いてみましたので、参考にしてください。ただ、ファイルをコピーまたは移動する部分(CopyFilesToDirectoryメソッド)はいい加減で、コピー先に同名のファイルが存在する時や、フォルダがコピーされた時のことを考えていないなど問題が多く、実用的ではありません。
''' <summary> ''' 指定したフォルダにコピーまたは切り取られたファイルを貼り付ける ''' </summary> Public Shared Sub PasteFiles(ByVal destDir As String) 'クリップボードのデータを取得する Dim data As IDataObject = Clipboard.GetDataObject() 'クリップボードにファイルドロップ形式のデータがあるか確認 If Not data Is Nothing AndAlso data.GetDataPresent(DataFormats.FileDrop) Then 'コピーされたファイルのリストを取得する Dim files As String() = DirectCast(data.GetData(DataFormats.FileDrop), String()) 'DragDropEffectsを取得する Dim dde As DragDropEffects = GetPreferredDropEffect(data) If dde = (DragDropEffects.Copy Or DragDropEffects.Link) Then 'ファイルがコピーされていた時 CopyFilesToDirectory(files, destDir, False) ElseIf dde = DragDropEffects.Move Then 'ファイルが切り取られていた時 CopyFilesToDirectory(files, destDir, True) End If End If End Sub ''' <summary> ''' クリップボードの"Preferred DropEffect"を調べる ''' </summary> Public Shared Function GetPreferredDropEffect(ByVal data As IDataObject) As DragDropEffects Dim dde As DragDropEffects = DragDropEffects.None If Not data Is Nothing Then 'Preferred DropEffect形式のデータを取得する Dim ms As System.IO.MemoryStream = _ DirectCast(data.GetData("Preferred DropEffect"), System.IO.MemoryStream) If ms IsNot Nothing Then '先頭のバイトからDragDropEffectsを取得する dde = DirectCast(ms.ReadByte(), DragDropEffects) If dde = (DragDropEffects.Copy Or DragDropEffects.Link) Then Console.WriteLine("コピー") ElseIf dde = DragDropEffects.Move Then Console.WriteLine("切り取り") End If End If End If Return dde End Function ''' <summary> ''' 複数のファイルを指定したフォルダにコピーまたは移動する ''' </summary> Public Shared Sub CopyFilesToDirectory(ByVal sourceFiles As String(), _ ByVal destDir As String, ByVal move As Boolean) For Each sourcePath As String In sourceFiles 'コピー先のパスを決定する Dim destName As String = System.IO.Path.GetFileName(sourcePath) Dim destPath As String = System.IO.Path.Combine(destDir, destName) If Not move Then 'ファイルをコピーする System.IO.File.Copy(sourcePath, destPath) Else 'ファイルを移動する System.IO.File.Move(sourcePath, destPath) End If Next End Sub
/// <summary> /// 指定したフォルダにコピーまたは切り取られたファイルを貼り付ける /// </summary> public static void PasteFiles(string destDir) { //クリップボードのデータを取得する IDataObject data = Clipboard.GetDataObject(); //クリップボードにファイルドロップ形式のデータがあるか確認 if (data != null && data.GetDataPresent(DataFormats.FileDrop)) { //コピーされたファイルのリストを取得する string[] files = (string[])data.GetData(DataFormats.FileDrop); //DragDropEffectsを取得する DragDropEffects dde = GetPreferredDropEffect(data); if (dde == (DragDropEffects.Copy | DragDropEffects.Link)) { //ファイルがコピーされていた時 CopyFilesToDirectory(files, destDir, false); } else if (dde == DragDropEffects.Move) { //ファイルが切り取られていた時 CopyFilesToDirectory(files, destDir, true); } } } /// <summary> /// クリップボードの"Preferred DropEffect"を調べる /// </summary> public static DragDropEffects GetPreferredDropEffect(IDataObject data) { DragDropEffects dde = DragDropEffects.None; if (data != null) { //Preferred DropEffect形式のデータを取得する System.IO.MemoryStream ms = (System.IO.MemoryStream)data.GetData("Preferred DropEffect"); if (ms != null) { //先頭のバイトからDragDropEffectsを取得する dde = (DragDropEffects)ms.ReadByte(); if (dde == (DragDropEffects.Copy | DragDropEffects.Link)) { Console.WriteLine("コピー"); } else if (dde == DragDropEffects.Move) { Console.WriteLine("切り取り"); } } } return dde; } /// <summary> /// 複数のファイルを指定したフォルダにコピーまたは移動する /// </summary> public static void CopyFilesToDirectory(string[] sourceFiles, string destDir, bool move) { foreach (string sourcePath in sourceFiles) { //コピー先のパスを決定する string destName = System.IO.Path.GetFileName(sourcePath); string destPath = System.IO.Path.Combine(destDir, destName); if (!move) { //ファイルをコピーする System.IO.File.Copy(sourcePath, destPath); } else { //ファイルを移動する System.IO.File.Move(sourcePath, destPath); } } }
(この記事は、「.NETプログラミング研究 第54号」で紹介したものを基にしています。)