0

I'm learning how to use Python and I decided to write a code off my head based on what I had learnt previously. I opened python IDLE shell and wrote this code to move txt files into a folder:

import os 
import shutil
 
folder = 'C:\Users\PROJECTPLUS\Desktop\Tolu's\TOLU'S\Personal\.py' 
destination = 'C:\Users\User\Desktop\Tolu's\TOLU'S\Personal\.py\.txt files'

for root, directory, files in os.walk(folder): 
    for file in files: 
        if file.endswith('.txt'): 
            shutil.move(file, destination) 
            print('files moved to ' + destination)re

upon execution, there was no error and the print() function was called on each file. the problem now is I can't find my txt files anywhere. I later realised that the folder I had created was named "txt files" (which is still empty) instead of ".txt files" as I had written in the code. I also realised there was a file document named ".txt files" that was last modified on 31/05/2023 in case that could have been the issue.

I don't know how to undo this nor do I know how to recover said files. if you have any suggestion, please help.

  • The destination you should revised the " and ' to ensure it is a str – Xiaomin Wu Jul 14 '23 at 09:57
  • Surely this is not your actual code. I get a syntax error on the `folder = ` line. – quamrana Jul 14 '23 at 10:05
  • 1
    The `folder` and `destination` strings have syntax errors: firstly, because of the embedded single quote and secondly because of the bogus unicode escape (if you're using Python 3). You should instead use double-quoted raw-strings: e.g. `r"C:\Users ... Personal\.py"`. – ekhumoro Jul 14 '23 at 10:12
  • the files are deleted (except for 1) because you renamed them all to ".txt files" one after the other as in my answer below – srn Jul 14 '23 at 11:00

2 Answers2

-1

Firstly, for moving files, the python code can be like this, slightly modified from yours to appropriately move to correct destination:

import os 
import shutil
 
# folder = "C:\\Users\\PROJECTPLUS\\Desktop\\Tolu\'s\\TOLU\'S\\Personal\\py\\"
# destination = "C:\\Users\\User\\Desktop\\Tolu\'s\\TOLU\'S\\Personal\\py\\txt\ files\\"

# folder = "C:\Users\PROJECTPLUS\Desktop\Tolu\'s\TOLU\'S\Personal\py\"
# destination = "C:\Users\User\Desktop\Tolu\'s\TOLU\'S\Personal\py\txt files\"

folder = "/Users/x/Downloads/data_for_llama2/"
destination = "/Users/x/Downloads/data_for_llama1/"

for root, directory, files in os.walk(folder): 
    for file in files: 
        if file.endswith('.txt'): 
            shutil.move(folder+file, destination) 
            print('files moved to ' + destination)

Also I have added some commented lines for your file paths, you can try like that.

Secondly, you have used .(dot) prefixed folder names, so in Windows most times it would be a hidden file/folder. Please try enabling/showing hidden files in file explorer in you desired location, then you can retrieve your files which got moved into those folders.

amrs-tech
  • 485
  • 2
  • 14
-1

TL;DR get your text files from a backup, try to find remnants of them with data recovery tools, change your code and learn from this.

And to increase chances of recovery, try to stop all write ops on that disk asap (and possibly ask a separate question in a fitting community of how to recover those files).

First, what happened:

  1. Giving that you cannot find your text files anymore, you executed the script from within the directory you call folder. The safe way to get the correct path is to join the root and the filename, for instance: source_path = os.path.join(root, file)

  2. This is because iterating over files ( for file in files ) from os.walk() you iterate only over the filenames, not their full path. Since you already were in their directory, the following shutil.move() still worked. Otherwise it would not have found file and thrown an exception.

  3. Instead of moving files to the folder (as it didn't exist), you renamed each file to .txt files (your destination). One after the other, replace the previous one. So this file now has the contents of the last file that was moved/renamed (and the timestamp stems from that file).

This seems to be a very typical (and serious) problem that people have when using any form of programmatic move operation. It's very frustrating, but the best you can do is use this as a learning opportunity.

A little bit of explanation from the shutil.move() docs:

If the destination is a directory or a symlink to a directory, the source
is moved inside the directory. The destination path must not already
exist.

If the destination already exists but is not a directory, it may be
overwritten depending on os.rename() semantics.

This is pretty straightforward, but can absolutely lead to confusion due to the difference of destination and destination path. One may wrongly assume from the first paragraph that moving to an existing path would always fail, while this is only true if the destination is a directory and thus the destination path a location within that directory. With the first iteration of your loop you renamed a file instead and subsequently your destination never became a directory and was handled as in the 2nd paragraph (overwritten).

What could you have done to avoid this?

Taken that the destination should have been a folder, you should have made (programmatically) sure that this folder actually exists. If it didn't, either throw an exception or create it.

This could have been done like this:

pathlib.Path(destination).mkdir(parents=True, exist_ok=True)

If destination (like in your case) did not exist previously, it would have created that directory. If a file of the same location had existed before, the program would have thrown a FileExistsError, which would have stopped the execution of the program (and thus stopped the damage).

Additionally, you could have checked explicitly whether the target destination already exists (to avoid overwriting other files). One of many ways to do that:

if not os.path.isdir(destination):
    # dest is not a dir, so shutil won't help us with the exist-check
    if not os.path.exists(destination):
        shutil.move(...)
    else:
        print('some debugging or raise an exception ...')
else:
    # here shutil will catch those exist errors for you
    shutil.move(...)

This may seem a little over the top, but better be safe than overwriting what you didn't want to overwrite.

You may also have done a dry-run first, in which you mock what shutil.move() is supposed to do and print the destination per move operation. This way you'd have seen that all files get the same destination and name and something was off.

srn
  • 614
  • 3
  • 15