merrymonk has asked for the wisdom of the Perl Monks concerning the following question:

Is there anything a Monk can ‘read’ in the system data or elsewhere of a PC that will give the maximum allowed length for the path and name of an Excel file (and other files as well as I guess I will need this in the future).
If so it would be good to have some clues as to how this is done.
The internet has sites that give various figures and I get the impression that the lengths may depend on the version of Excel and the operating system being used.
There is also some question of if a limit applies to the path and name individually or if the limit has to be applied to the path and name taken together.
Unfortunately the results from admittedly limited tests I have done do not seem to agree with what I have found on the internet.

Replies are listed 'Best First'.
Re: Path and File Name Maximum Lengths
by marto (Cardinal) on Jun 14, 2010 at 11:12 UTC

    From a file system perspective see Comparison_of_file_systems for both maximum file name length and Maximum pathname length. Perhaps Microsoft have documentation (I've always found their documentation to me messy IMHO) on any Excel related specifics.

Re: Path and File Name Maximum Lengths
by BrowserUk (Patriarch) on Jun 14, 2010 at 11:31 UTC

    There is a lot of misinformation around. See the horse's mouth for the details,

    A working approximation is 255 per path element with an overall max of 32767. But you need to use the "UNC syntax" (\\?\...) to avail yourself of the extended length.


    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.

      But you need to use the "UNC syntax" (\\?\...) to avail yourself of the extended length.

      In addition to using the "UNC syntax", one needs to use CreateFileW according to the documentation. It's my understanding that open uses CreateFileA, so Win32API::File or similar is required.

        Correct. It used to be that Perl supported (some) wide file apis, but they got dropped in order to support unicode on other platforms.

        If you want to create a totally impractical path with 32k chars, compile and run this. (WARNING: It is a bitch to delete!)

        #include <stdio.h> #include <windows.h> wchar_t path[ 32768 ] = L"\\\\?\\c:\\1234567890\\"; wchar_t name[] = L"1234567890\\"; int main( int argc, char **argv ) { while( CreateDirectoryW( path, NULL ) ) { wcscat( path, name ); }; printf( "Error %d\n", GetLastError() );; }

        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
Re: Path and File Name Maximum Lengths
by afoken (Chancellor) on Jun 14, 2010 at 15:17 UTC

    Perhaps http://www.foken.de/alexander/projekte/windows/deepcopy.html and especially #Algorithm may help you.

    Unfortunately the results from admittedly limited tests I have done do not seem to agree with what I have found on the internet.

    Why doesn't that surprise me? MS has failed to define an upper limit for the length of an absolute filename in the past. Many API functions have some arbitary limits, typically 256 or 260 chars, some newer APIs accept even longer names. Usually, there are many different APIs for the same purpose, with different limits and different features, two or three levels of legacy APIs (dating back to Win95, WinNT 4, Win3.x, and even DOS), ANSI and Unicode variants, different APIs for drive letter paths and UNC paths, and so on. This ends in applications like the Windows Explorer not being able to access files with absolute names longer than 260 chars.

    Lessons learned from that: If you can't avoid Windows, keep the paths short and without spaces, don't call API functions with more than 255 chars, but be prepared to get much longer paths back.

    Alexander

    --
    Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)

      MS has failed to define an upper limit for the length of an absolute filename in the past.

      MAX_PATH has been around for as long I can remember.

      Many API functions have some arbitary limits, typically 256 or 260 chars

      First you complain there's no limits, and then you call the limits arbitrary?

      Besides, the limit isn't arbitrary. 240 comes from history:

      Drive (C:\) + Dir (240) + 8.3 file name (12) + NUL = 256

      It has been expanded to allow a drive using the \\?\C:\ notation:

      Path (\\?\C:\ + 240 + 12) + NUL = 260.
        First you complain there's no limits, and then you call the limits arbitrary?

        Sorry, bad wording, I should have written "MS has failed to define a single, universal upper limit for the length of an absolute filename for all API functions in the past."

        MAX_PATH has been around for as long I can remember.

        And it does not say anything about the maximum length for an absolute filename any more. Even the 32767 chars limit is no real limit, according to http://msdn.microsoft.com/en-us/library/aa365247%28VS.85%29.aspx:

        Note The maximum path of 32,767 characters is approximate, because the "\\?\" prefix may be expanded to a longer string by the system at run time, and this expansion applies to the total length.

        And another quote:

        The shell and the file system have different requirements. It is possible to create a path with the Windows API that the shell user interface might not be able to interpret properly.

        And this is the point where the various file APIs really stink.

        Alexander

        --
        Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)
Re: Path and File Name Maximum Lengths
by jwkrahn (Abbot) on Jun 14, 2010 at 11:51 UTC
    $ perl -MPOSIX -le'print PATH_MAX' 4096

      Does Excel run on POSIX platforms?

        Thank you for the various answers. I could not find what I really wanted in the references. Therefore I wrote a simple test script (below) to try and find out what I was looking for. This creates directories with increasing numbers of characters in their names. It then writes spreadsheets in these directories again
        with increasing name lengths. A summary is printed out at the end of what is found. It seems that the limit is an overall total of about 219 characters and that the path and file name have to be included in this total.
        use strict; use OLE; use Win32::OLE::Const "Microsoft Excel"; my ($test_dir, $mkdir_res, $dir_name, $j, $k,$dir_length, $excel_name, + $full_excel_name, $full_excel_name_length); my ($excel, $workbook, $sheet, $excel_name, $full_excel_name_length, $ +full_excel_name, $excelsave_res, $excel_res); my (%config_data, $ext_length, %filedir_res, $test_dir_root); # the next line needs to have the extension for the normal Excel sprea +dsheet on the PC # this will be either .xls or .xlsx $config_data{cfg_quotation_spreadsheet_extension} = '.xlsx'; $ext_length = length($config_data{cfg_quotation_spreadsheet_extension} +); #================================================================== # # open spredsheet_for_excel_write # # this opens a new spredshert for use with the Excel wirting module # #================================================================== sub open_spreadsheet_for_excel_write($$$$) { my ($ref_excel, $ref_workbook, $ref_sheet, $ref_excel_res) = @_; my ($ew_obj_message, $err_dialog, $err_ans, $ew_message); $ew_obj_message = ''; eval {$$ref_excel = Win32::OLE->GetActiveObject( 'Excel.Application' ) + }; if( $@ ) { $ew_obj_message = "[open_spreadsheet_for_excel_write] Error: no E +xcel installed - message <$@>\n"; print "$ew_obj_message\n\n"; } else { print "[open_spreadsheet_for_excel_write] Excel installation test +passed\n"; } unless( defined $$ref_excel ) { # if not running, start it $$ref_excel = Win32::OLE->new('Excel.Application', 'Quit') or ($$r +ef_excel_res = 0, $ew_message = "Could not create excel object"); } else { $$ref_excel_res = 1; } $$ref_workbook = $$ref_excel -> Workbooks -> Add; $$ref_sheet = $$ref_workbook -> Worksheets("Sheet1"); $$ref_sheet -> {Name} = "Raw Costs"; $$ref_sheet -> Activate; } #===================================================================== +========== # # sub save spreadsheet # # #===================================================================== +=========== sub save_spreadsheet($$$$$$) { my ($ref_excel, $ref_workbook, $ref_sheet, $given_spsh_dir, $given_sps +h_name, $ref_save_res) =@_; my ($spsh_full, $given_spsh_dir_mod, $spsh_save, $ew_message, $excel_r +es, $en_err, $en_f, $en_num, $close_res, $delete_spsh_return_code); # save spreadsheet $$ref_excel->{DisplayAlerts}=0; $spsh_full = $given_spsh_dir . '/' . $given_spsh_name . '.xls'; $spsh_full =~ s/\:\\\\/\:\\/; $given_spsh_dir_mod = $given_spsh_dir; $given_spsh_dir_mod =~ s/\:\\\\/\:\\/; $ew_message = "[save_spreadsheet]just before saving part file <$spsh_f +ull>"; $spsh_save = $given_spsh_dir_mod . '/' . $given_spsh_name . $config_da +ta{cfg_quotation_spreadsheet_extension}; $spsh_save =~ s/\:\\\\/\:\\/; $ew_message = "\n[save_spreadsheet]just before saving spreadsheet file + <$spsh_save>"; $excel_res = 1; $$ref_excel->Workbooks(1)->SaveAs($spsh_save) or ($excel_res = 0, $ew +_message = "Could not save spreadsheet <$spsh_save>"); $$ref_save_res = $excel_res; } #=========main=================================================== open_spreadsheet_for_excel_write (\$excel, \$workbook, \$sheet, \$exce +l_res); print "excel <$excel> workbook <$workbook> sheet <$sheet>\n\n"; $test_dir = "c:\\\\filedir_test"; $mkdir_res = mkdir($test_dir); $test_dir .= "\\"; $test_dir_root = $test_dir; print "for root dir <$test_dir> made result <$mkdir_res>\n"; if($mkdir_res == 1) { # create directories for($j = 1; $j <= 300; $j ++) { $test_dir .= 'A'; $dir_length = length($test_dir); $mkdir_res = mkdir($test_dir); # print "directory length <$dir_length> make sucess <$mkdir_res +>\n"; if($mkdir_res == 1) { $filedir_res{$j}{MaxDirLength} = $dir_length; $excel_name = ''; for ($k = 1; $k <= 300; $k ++) { $excel_name = 'A' . $excel_name; $dir_length = length($excel_name) + $ext_length; $full_excel_name = $test_dir . '/' . $excel_name; $full_excel_name_length = length($full_excel_name) + $ +ext_length; $excelsave_res = 1; $excel->Workbooks(1)->SaveAs ($full_excel_name) or ( +$excelsave_res = 0); save_spreadsheet(\$excel, \$workbook, \$sheet, $test_d +ir, $excel_name, \$excelsave_res); # print " excel name <$full_excel_name> length <$dir +_length> full path length <$full_excel_name_length> result <$excelsav +e_res>\n"; if($excelsave_res == 1) { $filedir_res{$j}{ExcelNameLength} = $dir_length; $filedir_res{$j}{FullPathLength} = $full_excel_nam +e_length; } else { $k = 301; } } } else { $j = 301; } } } open (FILDIROP, ">" . $test_dir_root . "file directory length.txt"); print "MaxDirLength,ExcelNameLength,FullPathLength\n"; print FILDIROP"\n\nMaxDirLength,xcelNameLength,FullPathLength\n"; foreach $j (sort {$a <=> $b} keys %filedir_res) { print "$filedir_res{$j}{MaxDirLength},$filedir_res{$j}{ExcelNameLe +ngth},$filedir_res{$j}{FullPathLength}\n"; print FILDIROP "$filedir_res{$j}{MaxDirLength},$filedir_res{$j}{Ex +celNameLength},$filedir_res{$j}{FullPathLength}\n"; } close(FILDIROP);