Search code examples
python-3.ximagesubdirectory

Images don't open using Image.open(fnames) and code have " 'list' object has no attribute 'read' " error


I have some subfolders(s1,s2,s3,...). I want to open images in the subfolders in the "Image" folder in path:
"E:/Image/" and show them. But images can not be opened.

import os
from PIL import Image
root = "E:/Image/" 
path = os.path.join(root,"")
for r in os.walk(path):
     for file in r:
        fnames = glob.glob(f'{root}{r}/{file}')
        img1 = Image.open(fnames)
        img1.show()  

My code have this error:

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
~\Anaconda3\lib\site-packages\PIL\Image.py in open(fp, mode)
   2546     try:
-> 2547         fp.seek(0)
   2548     except (AttributeError, io.UnsupportedOperation):

AttributeError: 'list' object has no attribute 'seek'

During handling of the above exception, another exception occurred:

AttributeError                            Traceback (most recent call last)
<ipython-input-5-e9dafc96965e> in <module>()
      9         fnames = glob.glob(f'{root}{r}/{file}')
     10 
---> 11         img1 = Image.open(fnames)
     12        
     13         img1.show()

~\Anaconda3\lib\site-packages\PIL\Image.py in open(fp, mode)
   2547         fp.seek(0)
   2548     except (AttributeError, io.UnsupportedOperation):
-> 2549         fp = io.BytesIO(fp.read())
   2550         exclusive_fp = True
   2551 

AttributeError: 'list' object has no attribute 'read'

Solution

  • You get the exception because you pass a list to instead of a file name to Image.open.

    However the main issues that I see are related to the wrong use of os.walk and glob.glob. I suggest to carefully read the documentation before using a functionality that you don't know.

    A clarification:

    • os.walk doesn't return the name of the files in path but, recursively, a directory (dirpath), the list of subdirectories (dirnames) and the list of the files in the directory (filenames). You can get all the file names simply doing os.path.join(dirpath, name) for each name in in filenames.
    • glob.glob returns a list of files matching the given wildcards. From your code, I imagine that you expect that f'{root}{r}/{file}' is the name of a file on the system, so there is no need to complicate your life using glob.glob

    A a couple of notes:

    • since your root already has a trailing /, the call to os.path.join(root,"") does nothing;
    • if you want to create file paths programmatically, do not add path separators by hand, but try to use os.path.join (or if necessary os.sep) as much as possible (it helps to maintain cross-system compatibility). As example instead of doing

      root = "E:/Image/" 
      r = 'folder'
      file = 'test.txt'
      fname = f'{root}{r}/{file}'
      

      use

      root = "E:/Image" 
      r = 'folder'
      file = 'test.txt'
      fname = os.path.join(root, r, file)
      

    The code

    And now the "correct" code. Since I don't know your directory structure, user case and such, the code might now work as you want, but I hope that you can adapt it to your needs.

    import os
    from PIL import Image
    
    root = "E:/Image/" 
    for dirpath, _, filenames in os.walk(path):
        # we don't care about ``dirnames``
        for name in filenames:
            fname = op.path.join(dirpath, name)
            img1 = Image.open(fname)
            img1.show()