विंडोज पर विश्वसनीय File.renameTo () विकल्प?


92

जावा की File.renameTo()समस्याग्रस्त है, विशेष रूप से विंडोज पर, ऐसा लगता है। जैसा कि एपीआई प्रलेखन कहता है,

इस पद्धति के व्यवहार के कई पहलू स्वाभाविक रूप से प्लेटफ़ॉर्म-निर्भर हैं: नाम बदलने की प्रक्रिया एक फ़ाइल सिस्टम से दूसरे फाइल में स्थानांतरित करने में सक्षम नहीं हो सकती है, यह परमाणु नहीं हो सकती है, और यह सफल नहीं हो सकती है यदि गंतव्य सार पथ के साथ एक फ़ाइल पहले से ही मौजूद है। रिटर्न मान हमेशा यह सुनिश्चित करने के लिए जांचना चाहिए कि नाम बदलने का ऑपरेशन सफल रहा।

मेरे मामले में, एक अपग्रेड प्रक्रिया के हिस्से के रूप में, मुझे एक निर्देशिका को स्थानांतरित करने (नाम बदलने) की आवश्यकता है जिसमें डेटा के गीगाबाइट्स (बहुत सारे उपनिर्देशिका और अलग-अलग आकार की फाइलें) हो सकते हैं। चाल हमेशा एक ही विभाजन / ड्राइव के भीतर की जाती है, इसलिए डिस्क पर सभी फ़ाइलों को भौतिक रूप से स्थानांतरित करने की कोई वास्तविक आवश्यकता नहीं है।

वहाँ नहीं होना चाहिए निर्देशिका की सामग्री के किसी भी फाइल ताले स्थानांतरित करने की हो, लेकिन अभी भी, अक्सर, renameTo () अपना काम और रिटर्न झूठी करने के लिए विफल रहता है। (मैं सिर्फ अनुमान लगा रहा हूं कि शायद कुछ फ़ाइल ताले विंडोज पर कुछ मनमाने ढंग से समाप्त हो जाते हैं।)

वर्तमान में मेरे पास एक फालबैक विधि है जो कॉपी करने और हटाने का उपयोग करती है, लेकिन यह बेकार है क्योंकि फ़ोल्डर के आकार के आधार पर इसमें बहुत समय लग सकता है । मैं इस तथ्य पर भी विचार कर रहा हूं कि उपयोगकर्ता संभावित रूप से घंटों प्रतीक्षा करने से बचने के लिए फ़ोल्डर को मैन्युअल रूप से स्थानांतरित कर सकता है। लेकिन राइट वे स्पष्ट रूप से कुछ स्वचालित और त्वरित होगा।

तो मेरा सवाल यह है कि क्या आप विंडोज पर जावा के साथ एक त्वरित चाल / नाम बदलने के लिए एक वैकल्पिक, विश्वसनीय दृष्टिकोण जानते हैं , या तो सादे JDK या कुछ बाहरी पुस्तकालय के साथ। या यदि आप किसी दिए गए फ़ोल्डर और उसकी सभी सामग्रियों (संभवतः हजारों व्यक्तिगत फ़ाइलों) के लिए किसी भी फ़ाइल ताले का पता लगाने और जारी करने का एक आसान तरीका जानते हैं , तो यह भी ठीक होगा।


संपादित करें : इस विशेष मामले में, ऐसा लगता है कि हम renameTo()कुछ और चीजों को ध्यान में रखते हुए उपयोग कर रहे हैं; इस उत्तर को देखें ।


3
आप JDK 7 का इंतजार / उपयोग कर सकते हैं, जिसमें फ़ाइल सिस्टम का बेहतर समर्थन है।
एकरनोकड

@ kd304, वास्तव में मैं इंतजार नहीं कर सकता या एक शुरुआती एक्सेस संस्करण का उपयोग कर सकता हूं, लेकिन रास्ते में ऐसा कुछ जानना दिलचस्प है!
जोनिक

जवाबों:


52

Files.move()JDK 7 में विधि भी देखें ।

एक उदाहरण:

String fileName = "MyFile.txt";

try {
    Files.move(new File(fileName).toPath(), new File(fileName).toPath(), java.nio.file.StandardCopyOption.REPLACE_EXISTING);
} catch (IOException ex) {
    Logger.getLogger(SomeClass.class.getName()).log(Level.SEVERE, null, ex);
}

7
दुर्भाग्य से Java7 हमेशा जवाब नहीं है (जैसे 42 है)
14

1
Ubuntu, JDK7 पर भी, EBS भंडारण के साथ EC2 पर कोड चलाते समय हमें इस मुद्दे का सामना करना पड़ा। File.renameTo विफल रहा और इसलिए File.canWrite किया गया।
saurabheights 13

ध्यान रखें कि यह फ़ाइल # renameTo () के रूप में अविश्वसनीय है। यह विफल होने पर बस अधिक उपयोगी त्रुटि देता है। एकमात्र उचित विश्वसनीय तरीका जो मैंने पाया है कि फाइल को फाइल के साथ कॉपी करें # नए नाम पर कॉपी करें, और फिर फाइल का उपयोग करके मूल को हटाएं ।
jwenting

26

इसके लायक क्या है, कुछ और धारणाएँ:

  1. renameTo()यदि यह खाली है, तो भी विंडोज पर, लक्ष्य निर्देशिका मौजूद है, विफल लगता है। इसने मुझे आश्चर्यचकित किया, जैसा कि मैंने लिनक्स पर कोशिश की थी, जहां renameTo()लक्ष्य मौजूद होने तक सफल रहा, जब तक यह खाली था।

    (स्पष्ट रूप से मुझे यह नहीं मानना ​​चाहिए कि इस तरह का काम प्लेटफार्मों भर में एक ही काम करता है; यह वास्तव में जावदोक के बारे में चेतावनी है।)

  2. यदि आपको संदेह है कि कुछ सुस्त फ़ाइल ताले हो सकते हैं, तो चाल / नाम बदलने से पहले थोड़ा इंतजार करना मदद कर सकता है। (हमारे इंस्टॉलर / अपग्रेडर में एक बिंदु पर हमने "नींद" क्रिया और कुछ 10 सेकंड के लिए एक अनिश्चित प्रगति पट्टी को जोड़ा, क्योंकि कुछ फाइलों पर एक सेवा लटक सकती है)। शायद एक सरल रिट्रीट तंत्र भी करता है जो कोशिश करता है renameTo(), और फिर एक अवधि (जो शायद धीरे-धीरे बढ़ता है) की प्रतीक्षा करता है, जब तक कि ऑपरेशन सफल नहीं होता या कुछ समय समाप्त हो जाता है।

मेरे मामले में, अधिकांश समस्याओं को उपरोक्त दोनों को ध्यान में रखकर हल किया गया है, इसलिए हमें एक देशी कर्नेल कॉल या ऐसी कोई चीज़ करने की ज़रूरत नहीं है, सब के बाद।


2
मैं अभी के लिए अपना जवाब स्वीकार कर रहा हूं, क्योंकि यह बताता है कि हमारे मामले में क्या मदद मिली। फिर भी, यदि कोई व्यक्ति सामान्य नाम से अधिक नाम के साथ renameTo () के साथ आता है, तो बेझिझक पोस्ट करें और मुझे स्वीकार किए गए उत्तर पर पुनर्विचार करने में खुशी होगी।
जोनीक

4
6.5 साल बाद, मुझे लगता है कि इसके बजाय JDK 7 के उत्तर को स्वीकार करने का समय है , विशेष रूप से इतने सारे लोग इसे मददगार मानते हैं। =)
Jonik

19

मूल पोस्ट ने अनुरोध किया "विंडोज पर जावा के साथ एक त्वरित कदम / नाम बदलने के लिए एक वैकल्पिक, विश्वसनीय दृष्टिकोण या तो सादे JDK या कुछ बाहरी पुस्तकालय के साथ।"

एक अन्य विकल्प जिसका अभी तक उल्लेख नहीं किया गया है वह है v1.3.2 या बाद में apache.commons.io लाइब्रेरी, जिसमें FileUtils.moveFile () शामिल है

यह त्रुटि पर बूलियन को वापस करने के बजाय एक IOException फेंकता है।

इस दूसरे धागे में बड़ी लेप की प्रतिक्रिया भी देखें ।


2
इसके अलावा, ऐसा लगता है कि JDK 1.7 में बेहतर फाइलसिस्टम I / O समर्थन शामिल होगा। Check out java.nio.file.Path.moveTo (): java.sun.com/javase/7/docs/api/java/nio/file/Path.html
MykennaC

2
JDK 1.7 की कोई विधि नहीं हैjava.nio.file.Path.moveTo()
Malte Schwerhoff

5

मेरे मामले में यह मेरे अपने आवेदन के भीतर एक मृत वस्तु लग रही थी, जिसने उस फ़ाइल को संभाल रखा था। तो उस समाधान ने मेरे लिए काम किया:

for (int i = 0; i < 20; i++) {
    if (sourceFile.renameTo(backupFile))
        break;
    System.gc();
    Thread.yield();
}

लाभ: यह बहुत जल्दी है, क्योंकि थ्रेडस्लीप () एक विशिष्ट हार्डकोडेड समय के साथ नहीं है।

नुकसान: 20 की सीमा कुछ हार्डकोड नंबर है। मेरे सभी परीक्षणों में, i = 1 पर्याप्त है। लेकिन यह सुनिश्चित करने के लिए कि मैंने इसे 20 पर छोड़ दिया।


1
मैंने एक समान काम किया, लेकिन लूप में 100 मीटर की नींद के साथ।
लॉरेंस Dol

4

मुझे पता है कि यह थोड़ा हैकरी लगता है, लेकिन इसके लिए मुझे इसकी आवश्यकता है, ऐसा लगता है कि बफ़र्ड पाठकों और लेखकों के पास फाइल बनाने का कोई मुद्दा नहीं है।

void renameFiles(String oldName, String newName)
{
    String sCurrentLine = "";

    try
    {
        BufferedReader br = new BufferedReader(new FileReader(oldName));
        BufferedWriter bw = new BufferedWriter(new FileWriter(newName));

        while ((sCurrentLine = br.readLine()) != null)
        {
            bw.write(sCurrentLine);
            bw.newLine();
        }

        br.close();
        bw.close();

        File org = new File(oldName);
        org.delete();

    }
    catch (FileNotFoundException e)
    {
        e.printStackTrace();
    }
    catch (IOException e)
    {
        e.printStackTrace();
    }

}

पार्सर के हिस्से के रूप में छोटी पाठ फ़ाइलों के लिए अच्छी तरह से काम करता है, बस सुनिश्चित करें कि पुराना नाम और नया नाम फ़ाइल स्थानों के लिए पूर्ण पथ हैं।

चियर्स कैक्टस


4

निम्नलिखित कोड का कोड 'वैकल्पिक' नहीं है, लेकिन विंडोज और लिनक्स वातावरण दोनों पर मेरे लिए मज़बूती से काम किया है:

public static void renameFile(String oldName, String newName) throws IOException {
    File srcFile = new File(oldName);
    boolean bSucceeded = false;
    try {
        File destFile = new File(newName);
        if (destFile.exists()) {
            if (!destFile.delete()) {
                throw new IOException(oldName + " was not successfully renamed to " + newName); 
            }
        }
        if (!srcFile.renameTo(destFile))        {
            throw new IOException(oldName + " was not successfully renamed to " + newName);
        } else {
                bSucceeded = true;
        }
    } finally {
          if (bSucceeded) {
                srcFile.delete();
          }
    }
}

2
हम्म, यह कोड srcFile को तब भी हटा देता है, जब renameTo (या destFile.delete) विफल हो जाता है और विधि IOException को फेंक देती है; मुझे यकीन नहीं है कि अगर यह एक अच्छा विचार है।
जोनिक

1
@Jonik, Thanx, नाम बदलने में विफल रहने पर src फ़ाइल को हटाने के लिए निश्चित कोड।
पागल घोड़े

यह विंडोज़ पर मेरे नाम बदलने के मुद्दे को साझा करने के लिए धन्यवाद।
बिलमैन

3

खिड़कियों पर मैं का उपयोग करें Runtime.getRuntime().exec("cmd \\c ") और फिर कमांडलाइन नाम बदलें फ़ंक्शन का उपयोग वास्तव में फ़ाइलों का नाम बदलने के लिए करता । यह बहुत अधिक लचीला है, उदाहरण के लिए यदि आप डीएआर में सभी txt फ़ाइलों के एक्सटेंशन का नाम बदलना चाहते हैं तो इसे आउटपुट के लिए लिखें:

नाम बदलकर .txt * .bak

मुझे पता है कि यह एक अच्छा समाधान नहीं है, लेकिन जाहिरा तौर पर इसने हमेशा मेरे लिए काम किया है, बहुत बेहतर तो जावा इनलाइन समर्थन।


सुपर, यह बहुत बेहतर है! धन्यवाद! :-)
गफ्फाक

2

क्यों नहीं....

import com.sun.jna.Native;
import com.sun.jna.Library;

public class RenamerByJna {
    /* Requires jna.jar to be in your path */

    public interface Kernel32 extends Library {
        public boolean MoveFileA(String existingFileName, String newFileName);
    }

    public static void main(String[] args) {
        String path = "C:/yourchosenpath/";
        String existingFileName = path + "test.txt";
        String newFileName = path + "renamed.txt";

        Kernel32 kernel32 = (Kernel32) Native.loadLibrary("kernel32", Kernel32.class);
            kernel32.MoveFileA(existingFileName, newFileName);
        }
}

nwindows 7 पर काम करता है, अगर मौजूदाफाइल मौजूद नहीं है तो कुछ भी नहीं करता है, लेकिन जाहिर है कि इसे ठीक करने के लिए बेहतर साधन हो सकते हैं।


2

मेरा मुद्दा भी ऐसा ही था। फ़ाइल को विंडोज पर स्थानांतरित करने के बजाय कॉपी किया गया था लेकिन लिनक्स पर अच्छी तरह से काम किया। मैंने renameTo () को कॉल करने से पहले खोले गए फ़ाइल InputStream को बंद करके समस्या को ठीक किया। Windows XP पर परीक्षण किया गया।

fis = new FileInputStream(originalFile);
..
..
..
fis.close();// <<<---- Fixed by adding this
originalFile.renameTo(newDesitnationForOriginalFile);

1

मेरे मामले में, त्रुटि मूल निर्देशिका के पथ में थी। शायद एक बग, मुझे एक सही रास्ता पाने के लिए प्रतिस्थापन का उपयोग करना पड़ा।

        try {
            String n = f.getAbsolutePath();
            **n = n.substring(0, n.lastIndexOf("\\"));**
            File dest = new File(**n**, newName);
            f.renameTo(dest);
        } catch (Exception ex) {
           ...

0

मुझे पता है कि यह बेकार है, लेकिन एक विकल्प एक बल्ले स्क्रिप्ट बनाने के लिए है जो "SUCCESS" या "ERROR" जैसी सरल सामग्री का उत्पादन करता है, इसे लागू करें, इसे निष्पादित करने की प्रतीक्षा करें और फिर इसके परिणामों की जांच करें।

Runtime.getRuntime ()। Exec ("cmd / c start test.bat");

यह धागा दिलचस्प हो सकता है। किसी भिन्न प्रक्रिया के कंसोल आउटपुट को पढ़ने के तरीके के बारे में प्रक्रिया वर्ग की भी जाँच करें।


-2

आप रोबोकॉपी की कोशिश कर सकते हैं । यह बिल्कुल "नामकरण" नहीं है, लेकिन यह बहुत विश्वसनीय है।

रोबोकॉपी को निर्देशिका या निर्देशिका पेड़ों की विश्वसनीय मिररिंग के लिए डिज़ाइन किया गया है। इसमें सभी NTFS विशेषताओं और संपत्तियों की नकल करने की सुविधा है, और व्यवधान के अधीन नेटवर्क कनेक्शन के लिए अतिरिक्त पुनरारंभ कोड भी शामिल है।


धन्यवाद। लेकिन चूंकि रोबोकॉपी एक जावा लाइब्रेरी नहीं है, इसलिए शायद यह मेरे जावा कोड से बहुत आसान नहीं होगा (इसे बंडल करें) और इसका इस्तेमाल करें ...
जोनीक

-2

एक फ़ाइल को स्थानांतरित करने / नाम बदलने के लिए आप इस फ़ंक्शन का उपयोग कर सकते हैं:

BOOL WINAPI MoveFile(
  __in  LPCTSTR lpExistingFileName,
  __in  LPCTSTR lpNewFileName
);

इसे कर्नेल 32.dll में परिभाषित किया गया है।


1
मुझे लगता है कि जेएनआई में इसे लपेटने की परेशानी से गुजरना एक प्रक्रिया डेकोरेटर में रोबोकॉपी को लपेटने के प्रयास से अधिक है।
केविन Montrose

हां, यह वह मूल्य है जो आप अमूर्त के लिए भुगतान करते हैं - और जब यह लीक होता है, तो यह अच्छा होता है = डी
ची

धन्यवाद, मैं इस पर विचार कर सकता हूं यदि यह बहुत जटिल नहीं है। मैंने कभी जेएनआई का उपयोग नहीं किया, और एसओ पर विंडोज कर्नेल फ़ंक्शन को कॉल करने के अच्छे उदाहरण नहीं मिल सके, इसलिए मैंने यह सवाल पोस्ट किया: stackoverflow.com/questions/1000723/…
जोनिक

आप johannburkard.de/software/nativecall जैसे सामान्य जेएनआई आवरण की कोशिश कर सकते हैं क्योंकि यह एक बहुत ही सरल फ़ंक्शन कॉल है।
पीटर स्मिथ

-8
 File srcFile = new File(origFilename);
 File destFile = new File(newFilename);
 srcFile.renameTo(destFile);

ऊपर सरल कोड है। मैंने विंडोज 7 पर परीक्षण किया है और पूरी तरह से ठीक काम करता है।


11
ऐसे मामले हैं जहां renameTo () मज़बूती से काम नहीं करता है; यह सवाल का पूरा बिंदु है।
जोनिक
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.