1s 8.3 create a temporary file. Working with temporary files and directories
The 1C:Enterprise 8 technology platform allows you to save arbitrary files in the information base, retrieve them from there and use them in various ways. Let's look at these operations using examples.
Before uploading a file to the 1C information base, you need to obtain full address file on disk. Working with file selection dialogs is described in .
To store files, use an attribute (or register resource) with the type StorageValues.
Uploading an arbitrary file to the 1C information base
Any file can be represented as binary data and loaded into Value Storage.
When converting binary data to an object StorageValues design used new StorageValues(Data, Compression) with two parameters:
- Data— binary data that needs to be stored in storage
- Compression— compression ratio of the Deflation algorithm. Integer in the range -1...9. -1 is the default compression level. 0 - no compression, 9 - maximum compression. Default value: -1. The parameter is optional; if not specified, then compression is not used.
//Convert the file to binary data
File = New BinaryData(Path) ;
//Create a new Value Storage object
DataStorage = NewValueStorage(File, NewDataCompression(9) ) ;
Saving an arbitrary file from the 1C infobase to disk
To save a file from the 1C database to disk, you need to determine the path and file name. To do this, there is a file saving dialog, working with which is described in.
//Get binary data from storage
//Data Storage - attribute of an object with the Value Storage type
//Write the received data to disk
//The Path variable contains the full address of the file on disk
Data. Write(Path) ;
Viewing a file located in the 1C information base
To view a file saved in the database, you must have an application installed on your computer that opens the file.
//Get the name of the temporary file with the required extension
//In the Extension variable you need to put the file extension, for example "pdf"
Path = GetTemporaryFileName(Extension) ;
//Receive data from storage
//Data Storage - attribute of an object with the Value Storage type
Data = Datastore. Get() ;
//Write data to a temporary file
Data. Write(Path) ;
//Trying to open the file in the intended application
//If the application is not found, the system dialog "Open with..." will appear.
LaunchApplication(Path) ;
Scope of application: managed application, mobile application, a common application.
1. When accessing files and directories of the file system from the configuration code, you should keep in mind that access to them is limited by user rights operating system, on behalf of which the application is running.
1.1. If access to file system carried out from code running on the client, it is executed under the rights of the user on whose behalf the application is running (thin, thick or web client). Typically, this is the current user of the operating system.
1.2. If the file system is accessed from code running on the server, then:
- when using client-server information base, access is limited by the rights of the user on whose behalf the 1C:Enterprise server is running (*);
- when using file database published on a web server, access is limited by the rights of the user on whose behalf the web server is running.
Working with temporary files and directories
If you need to use temporary files and directories, you must comply with the following requirements:
1. To get the name of the temporary file, use the method GetTemporaryFileName. Otherwise, the configuration may not work correctly in multi-user mode, with security profiles enabled, and problems may arise with access rights to operating system files.
Wrong:
IntermediateFileName = "C:/Temporary files 1C/TempFile.xml"Data.Write(IntermediateFileName);
U current user You may not have write permission to the specified directory. Additionally, running this code from two different sessions at the same time will throw an error.
Right:
IntermediateFileName = GetTemporaryFileName("xml");Data.Write(IntermediateFileName);
When using this function, a unique name will be obtained and access to the file is guaranteed.
2. To create a temporary directory, it is also recommended to use the name obtained using the method GetTemporaryFileName. This ensures that the name of the created directory is unique when working in multi-user mode. After this, you can create other directories and files within the created directory without restrictions.
3. When executing code on a web client or in rare cases, if it is not required to ensure operation in multi-user mode, for example, updating a file information database, monopoly mode), you must use the function to form the file or directory name Directory of Temporary Files.
See alsoFeatures of developing configurations for Linux OS, about the peculiarities of using file names and paths.
4. After finishing working with the temporary file or directory, you must delete it yourself. You can't count on automatic removal files and directories the next time you start the platform, this may lead to exhaustion free space in the temporary files directory.
IntermediateFileName = GetTemporaryFileName("xml");Data.Write(IntermediateFileName);//Working with the file...//Deleting the temporary fileAttempting to Delete Files(IntermediateFileName);Exception LogRegistration(НStr("ru = "My mechanism.Action"") , LogLevel.Error, ErrorDetailView(ErrorInfo()));EndAttempt;
See also:Using the Log Book.
5. When using temporary files and directories on the server, you must completely terminate work with them within one server call. When running a configuration using a server cluster, the next time you call these files, these files may become inaccessible, since the code will start executing on another computer. If you need to save data between server calls within the same session, you should use the platform's temporary storage (methods , ).
5. 1. In rare cases, it may be necessary to transfer data in temporary files between sessions, for example, when preparing data for background job, when organizing a long-running process that serves several consecutive calls to a web service. It is necessary to independently provide guaranteed shared storage space, rights to access files from different places their processing, deleting files upon expiration of their processing time or abnormal termination of the processing process. The following approach is recommended:
- To ensure access from all possible processing locations, a constant is created to store a common path to files that can be accessed from all servers in the cluster;
- When temporary files are created, their names are entered into the auxiliary information register, preserving the time the file was created;
- During the normal course of the process, the last operation that needed files, before its completion, deletes both the file itself and the entries about them in the auxiliary register;
- The auxiliary routine task periodically checks for the presence of entries in the auxiliary register, the lifetime of which obviously exceeds the normal completion time of the process. When such entries are detected, the task deletes temporary files and entries about them.
Transferring files between client and server
1. When working with a file on the client and server simultaneously, you must use file transfer through temporary storage (methods PlaceFile, PlaceFiles, GetFile, GetFiles, StartFilePlace, Place in Temporary Storage, Receive From Temporary Storage). In general, the client and cluster servers are different computers with different file systems, and access to files can occur under different OS users with different rights.
Wrong:
&OnClientProcedureFileProcessing() ...FileName = "C:/Files for processing/Download.xml"; Result = Perform ProcessingOnServer(FileName); ...EndProcedure&OnServerFunction PerformProcessingOnServer(FileName) Reading = NewTextReading(FileName) ... Result = Reading.Read(); Return Result;EndFunction
Right:
&OnClientProcedureFileProcessing() ...FileNameForProcessing = "C:/Files for processing/Download.xml"; Address = ""; PlaceFile(Address, FileNameForProcessing, FileNameForProcessing, False); Result = Perform ProcessingOnServer(Address); ...EndProcedure&OnServerFunction PerformProcessingOnServer(Address) Data = GetFromTemporaryStorage(Address) IntermediateFileName = GetTemporaryFileName("txt"); Data.Write(IntermediateFileName); Read = New ReadText(IntermediateFileName) ... Result = Read.Read(); ...DeleteFiles(IntermediateFileName); Return Result;EndFunction
2. To save data in temporary storage between several server calls, when placing it in storage, you must use the parameter UniqueFormIdentifier method PlaceFile by passing the identifier of the current form into it. Such values will be deleted from their temporary storage only when the specified form is closed. In this case, when placing the same file in temporary storage again, the previous value must be deleted manually. For example:
Wrong:
FileNameForProcessing = "C:/Files for processing/Download.xml"; ... // First server call Address = ""; PlaceFile(Address, FileNameForProcessing, FileNameForProcessing, False, UniqueIdentifier); Result = Perform InitialProcessingOnServer(Address);
... // Second server call with the same file version Result = Perform IntermediateProcessingOnServer(Address); ...
// Third server call with new version file Address = ""; PlaceFile(Address, FileNameForProcessing, FileNameForProcessing, False, UniqueIdentifier); Result = Perform FinalProcessingOnServer(Address); ...
This will leave two copies of the files in the form's temporary storage. The address of the second copy will be in the variable Address, and the address of the first copy will be lost. This leads to the consumption of additional application resources and slowdowns.
Right:
FileNameForProcessing = "C:/Files for processing/Download.xml"; ... // First server call Address = ""; PlaceFile(Address, FileNameForProcessing, FileNameForProcessing, False, UniqueIdentifier); Result = Perform InitialProcessingOnServer(Address); ... // Second server call with the same file version Result = Perform IntermediateProcessingOnServer(Address); ...
// Third server call with a new version of the file DeleteFromTemporaryStorage(Address); Address = ""; PlaceFile(Address, FileNameForProcessing, FileNameForProcessing, False, UniqueIdentifier); Result = Perform FinalProcessingOnServer(Address); ...
See also
They find us: access to file system, GetTemporaryFileName(
I'll tell you a case from my practice. One day I had to set up data upload to 1C:Accounting from a non-replicated configuration. The unloading was in the form of a separate processing, working according to the exchange rules. The rules themselves were attached as a binary data layout. The operating algorithm is typical - the rules are uploaded to a temporary file, and then pulled up by processing " Universal exchange data in XML format."
The developer of the transfer rules and processing beat his chest and swore that everything was working perfectly for him. In practice, an error constantly occurred during data upload. The text of the error message openly stated that the problem lies in the exchange rules. “The document no longer has this property, I refuse to upload it,” read the text of the message. I didn’t want to tinker with the exchange rules, because... It's not my job. Instead, I opened the processing code and decided to see how the process of uploading exchange rules to a temporary file was organized.
It turned out that this was exactly the problem. The fact is that the programmer did not bother to make a unique file name for the exchange rules (in the temporary directory), and even inserted a check: “If the file exists, then uploading is not required.” Of course, everything worked until processing, or rather the layout with the rules was not updated. As a result, users constantly tried to upload using outdated exchange rules. The “temporary file” in the “temp” directory has become permanent and until you delete it manually, it will always be used for uploading.
You need to create temporary files correctly
To avoid such funny situations, you should not try to reinvent wheels and crutches in the form of “tricky” functions that use COM objects. It is enough to use the function built into the platform - GetTemporaryFileName(), which automatically solves many problems:
Ensures that the file name is truly unique;
If a developer forgets to delete a file himself, it will definitely be deleted the next time the platform is launched.
Automatic deletion of temporary files during a platform restart is a very interesting feature, which theoretically allows the developer to ignore the need to delete files themselves. True, it’s still not worth abusing it. If the code is executed on the server, then you need to understand that the server may not restart for a long time, which means temp folder will clog unnecessary files. In this regard, you should not completely trust the “dirty” work to the platform. It’s better to use this feature as a fallback option, and add one extra line of code to your code for forced deletion temporary file.
Very often, users experience strange errors: the program works correctly for one user, but for another, nearby, on another computer, it works completely differently. Often, after lengthy investigations, it turns out that the cause of such “glitches” in 1C 8 is the cache.
Below I will tell you what the 1C cache is and how to clear it.
Caching— the process of creating a buffer of frequently used and, as a rule, static information. Caching is used to speed up the program; in particular, in 1C, configuration files are loaded onto the user’s computer so as not to request them from the server every time.
However, very often the 1C platform does not handle configuration caching correctly, and as a result we get inappropriate configuration behavior.
The reasons for incorrect behavior can be different: dynamic configuration updates, software or hardware failures.
The first method is to clear the 1C cache manually
To solve problems and “glitches” of 1C, clearing the cache of the 1C 8.3 platform usually helps.
This is done as follows:
step 1
Find the directory where temporary 1C files are stored, they can be seen in the settings menu in the IB list:
Step 2
We got an address like
Get 267 video lessons on 1C for free:
C:\Documents and Settings\username\Application Data\1C\1Cv82\tmplts\1c
Cache folders are located at
C:\Documents and Settings\username\Application Data\1C\1Cv82\
*where username is the system user name, and the 1Cv82 folder may differ depending on the version of the 1C platform
Having gone there, we find many (the number of folders is equal to the number of configurations) interesting folders:
All selected directories are a 1C database cache and can be safely deleted. Before deleting, you must exit the information security system.
If you don't want to search for where the files are located, you can use special program(bat file), which cleans folders with temporary files - download . Please remember that you use them at your own risk. They contain the following command:
rmdir "%AppData%\1C\1Cv8" /S /Q
rmdir "%LOCALAPPDATA%\1C\1Cv8" /S /Q
The second way to clear 1C temporary files is to remove the database from the list
The second method is simpler, but it is not entirely correct. To clean it, just delete this configuration and create a new one with the same path to information security.
As a result, the old folder with the cache will be “unlinked” from this information security, and a new directory will be created.
You can do this, the cache is cleared, but temporary files remain on the hard drive.
The third method is the ClearCache parameter
It is necessary to enter the command in the additional launch parameters (in the list of databases, the Change button, the last tab) /ClearCache. Usage example:
Video on clearing cache in 1C programs:
If the “glitches” in 1C do not disappear after clearing the cache, and 1C does not work as you would like, you can turn to.
If you are starting to learn 1C programming, we recommend our free course(don't forget subscribe to YouTube - new videos are released regularly):
So, what is the point of my article?
1. There is a server (x64), with Office 2016 (x64) installed, there is 1C 8.3.8 also x64 (meaning 1C server). Users connect via both a thin client and a web client.
2. There are a bunch of standard contracts and invoices issued (prepared) by the sales department. There is a font, a paragraph, etc., of course, everything is designed in Word, Excel 2016 (x64), naturally, there is no desire to draw all this in 1C, but there is a desire to put it in ActiveDocument format layouts
The solution seems banal :) , I will not describe the entire mechanism, how it is done, how data is filled from 1C into the ActiveDocument layout - I think you know this perfectly well without me. But during the work it became clear that not everything is so smooth in the kingdom COM object ov, namely:
2. Which option is better to choose: ActiveDocument or Binary Data? Although to me it sounds something like choosing Vodka With Beer or Beer With Vodka :) . No big deal, you need to fill the documents with data from 1C and transfer them to the Client.
Well, okay, let’s skip the lyrics, I choose ActiveDocument, I won’t describe the entire algorithm, I’ll just list the pitfalls and their solution. Everything stated below is my personal speculation and in no way claims to be the ultimate truth. You may have solved these problems or solved them differently.
1. Stone " first". The SaveAs method does not work (for both MSWord and MSExcel). When trying to write Binary Data, 1C simply crashes. Look at the listing fragment:
MSWord = Layout.Get(); Try Document = MSWord.Application.Documents(1); Document.Activate(); //Next, we somehow get the data and fill out the Word document //Get the path in the temporary directory to save the file there TimeName = GetTemporaryFileName(".docx"); Document.SaveAs(NameTime); //stone begins here MyDocumentInBinaryData = New BinaryData(NameTime); //well, here this stone is knocked out by 1C :) MSWord.Application.Quit();
Thanks a lot.
Creating folders
C:\Windows\SysWOW64\config\systemprofile\Desktop
C:\Windows\System32\config\systemprofile\Desktop
the problem was solved. Topic closed.
What is the reason? The reason is that the code
MSWord = Layout.Get();
Always calls an instance of a COM object (x32), regardless of what bitness Office is installed. Have you ever wondered why you can’t insert files with the extension docx, xlsx into the ActoveDocument layout?
this can also be checked through the Task Manager, but the fact is that the ActiveDocument layout implicitly calls a COM instance (x32) and therefore all further manipulations must be done taking this feature into account.
1. Either the server and all software must be x32. Then you don’t need to do anything (in the sense of rewriting the code)
2. Either rewrite the code this way
// get the name of the temporary file TimeFile = GetTemporaryFileName("doc"); // this code will definitely call a COM instance of the required bit depth, in our case x64 Word = New COMObject("Word.Application"); Word.Displayalerts = 0; DocumentN = Word.Application.Documents.Add(); DocumentN.SaveAs(TimeFile,0); Word.Quit(); // then everything is as before Layout = Print Management. Printing Form Layout ("Document. Equipment Transfer Act." + Layout Name); MSWord = Layout.Get(); Try Document = MSWord.Application.Documents(1); Document.Activate(); // here we do something, fill in the data // here we will resave our file from COM x62 to COM x64 MSWord.Application.Selection.WholeStory(); MSWord.Application.Selection.Copy(); DocumentN = MSWord.Application.Documents.Open(TimeFile); DocumentH.Activate(); MSWord.Application.Selection.Paste(); DocumentN.SaveAs(TimeFile,0); DocumentN.Close(); MSWord = Undefined; Exception // If an error occurs, error data is printed and the object is closed. Information = ErrorInfo(); GeneralPurposeClientServer.NotifyUser("Error - "+Information.Description+" error code - "+Abb.LP(Information.SourceString)); MSWord.Application.Quit(); EndAttempt;
I think everything is clear here, first we created a COM instance of the required bit depth, created an empty file and saved it to a temporary folder, then we work with COM x32, fill it with data and finally copy the contents of the entire document and save it to a previously prepared file.
Everything is the same, but only for Excel
TimeFile = GetTimeFileName("xls"); Excel = New COMObject("Excel.Application"); Excel.Displayalerts = 0; BookH = Excel.WorkBooks.Add(); SheetN = BookN.WorkSheets(1); BookN.SaveAs(TimeFile, -4143); Excel.Quit(); Layout = PrintManagement.PrintFormLayout("Document.Equipment Invoice."+LayoutName); MSExcel = Layout.Get(); BookN = MSExcel.Application.Workbooks.Open(TimeFile); SheetN = BookN.WorkSheets(1); Trying WBook = MSExcel.Application.Workbooks(1); Sheet = WBook.WorkSheets(1); Sheet.Activate(); // do something, fill it with data from 1C MSExcel.Application.WorkBooks(1).WorkSheets(1).Cells.Copy(SheetN.Cells); BookN.Save(); BookN.Close(); Exception // If an error occurs, error data is printed and the object is closed. Information = ErrorInfo(); GeneralPurposeClientServer.NotifyUser("Error - "+Information.Description+" error code - "+Abb.LP(Information.SourceString)); MSExcel.Application.Quit(); EndAttempt;
Here you go " first“I decided the stone, on an x64 server with Office x64, everything works exactly like clockwork, without errors and there is no need to create any folders and everything else.
Stone " second". code snippet
TimeFile = GetTimeFileName("xls");
eating is not very good, because it writes to the folder: “c:\Users\ what’s there...”, in general, this folder is always on the black list of all firewalls, antiviruses, etc., etc., at least open the security control center in Word or Excel. Let's look there too
You will have to tinker with this, otherwise there is a possibility of “strange” errors appearing. Therefore I suggest the following:
1. Open the Configurator and add a new Information Register
here we will store our finished Word, Excel files already filled in, of course:
LayoutName - Layout ID
DocumentOffice - Value Storage, here we keep our finished file
2. We add the above code as follows:
MH = Information Registers.TemporaryStorageOffice.CreateRecordManager(); MH.Object = Selection.Link; MZ.LayoutName = LayoutName; MZ.Read(); MH.Object = Selection.Link; MZ.LayoutName = LayoutName; MZ.DocumentOffice = NewValueStorage(NewBinaryData(TimeFile)); MZ.Write(); DeleteFiles(TimeFile);
What we do is we write the finished file to the information register and then delete the temporary file itself, solving the “Word, Excel Security Center” problem. All that remains is to show this finished file to the Client (thin and web clients)
3. Stone " third" - transferring a file to the client, here I’ll just post all the code, some taken from the BSP, some from the Demo configuration " Managed Application", something from the Internet, but in general here is the code (in its entirety)
//////////////////////////////////////////////// //////////////////////////// // SERVICE PROCEDURES AND FUNCTIONS BSP &OnServer Function GetLayout() ObjectLink = DataStructure.Object; LayoutName = DataStructure.LayoutName; RecordKey = InformationRegisters.OfficeTemporaryStorage.CreateRecordKey( New Structure("Object,LayoutName",ObjectLink,LayoutName)); // Address = GetNavigationLink(RecordKey,"OfficeDocument"); Return Address; EndFunction // &OnClient Procedure AfterApplicationStart(ReturnCode, ApplicationName) Export; // End of the Procedure &On the Client Procedure After Receiving Files (Transferred Files, Additional Parameters) Export If NOT Transmitted Files = Undefined Then For each Description of the Transmitted Files Cycle OpAfterAppLaunch = New Alert Description("AfterAppLaunch", ThisObject, Description.Name); StartLaunchApplication(OpAfterStartApplication, Description.Name); EndCycle; endIf; EndProcedure &OnClient Procedure AfterDirectorySelection(SelectedFiles, CommandName) Export If SelectedFiles = Undefined Then Return; endIf; Directory = SelectedFiles; GeneralPurposeServerCall.SaveWorkingDirectory(Directory); If CommandName = "Invoice" Then LayoutName = "Invoice" EndIf; DataStructure.Insert("Directory", Directory); ConnectWaitingHandler("Connectable_SendFileToClient",5,True); End of Procedure &On the Client Procedure Open Files Through Extension (Command Name) OpAfterSelectingDirectory = New DescriptionAlerts("AfterSelectingDirectory", ThisObject, CommandName); Directory = GeneralPurposeCallServer.GetWorkingDirectory(); If Directory = Undefined OR Directory = "" Then Dialog = New FileSelectionDialog(FileSelectionDialogMode.DirectorySelection); Dialog.Header = НStr("ru = "Selecting a directory for temporary storage of files"", "ru"); Dialog.Show(OpAfterSelectingDirectory); Else SelectedFiles = New Array; SelectedFiles.Add(Directory); Perform Alert Processing(OpAfterSelectingDirectory, SelectedFiles); endIf; End of Procedure &On the Client Procedure ProcessConnectingExtensionsWorkingWithFiles(ExtensionConnected,AdditionalParameters) ExportIfExtensionConnectedThenOpenFilesThroughExtension(AdditionalParameters.CommandName); endIf; EndProcedure &OnClient Procedure Connected_PassFileToClient() Address = GetLayout(); If Address<>Undefined Then DisableWaitHandler("Connectable_SendFileToClient"); DocumentNumber = DataStructure.DocumentNumber; Directory = DataStructure.Directory; LayoutName = DataStructure.LayoutName; FilePath = Directory+"\"+LayoutName+"_No"+DocumentNumber+".xls"; Description = New Description of the Transmitted File (Path to File, Address); TransferredFiles = New Array; TransferredFiles.Add(Description); StartReceivingFiles(NewDescriptionAlerts("AfterReceivingFiles", ThisObject), TransferredFiles, "", False); endIf; End of Procedure &On the Server Procedure ExecutePrintServer() ObjectLink = DataStructure.Object; LayoutName = DataStructure.LayoutName; DataStructure.Insert("DocumentNumber", ObjectReference.Number); ObjectArray = New Array; Array of Objects.Add(ObjectRef); Documents.Equipment Invoice.PrintInvoice(Object Array,LayoutName,True); EndProcedure &OnClient Procedure Connectable_ExecutePrint() ExecutePrintServer(); EndProcedure // StandardSubsystems.Print &OnClient Procedure Connectable_ExecutePrintCommand(Command) Link = Elements.List.CurrentData.Link; DataStructure = newStructure; DataStructure.Insert("Object", Link); DataStructure.Insert("LayoutName", "Invoice"); ConnectWaitingHandler("Connectable_Print", 1, True); CommandDescription = PrintManageClient.PrintCommandDescription(Command.Name,FormName); Start Installing FileWorking Extension(); StartConnectingFileWorkingExtension(NewAlertDescription("ProcessConnectingFileWorkingExtension",ThisObject,NewStructure("CommandName",CommandDescription.Identifier))); EndProcedure // End StandardSubsystems.PrintA few clarifications:
1. Firstly, our client works through both Thin and Web modes, so in advance we set the following values in the Configurator properties:
To avoid problems when working with the browser
2. We use wait handlers to avoid problems with call synchronization (this only applies to Web mode)
3. And lastly, connect the Extension for working with Files (remember that in Thin Client mode, this extension is always enabled). And through the code:
we transfer the file to the Client using the NavigationLink mechanism, we receive the following messages in the browser (Thin works by itself):
Well, that seems to be all. Hope this helps someone...
Regarding Word, Excel files inserted as Binary Data? what's the problem?
1. We either have to pull out this Binary Data from the layout and fill it with data from 1C and ATTENTION write it down again in the form of Binary Data (Vodka With Beer or Beer With Vodka)
2. Either we must get the BinaryData layout on the Client side and fill it there, BUT the COM object is supported only by the IE browser and then with dances with ActiveX settings, other browsers have long abandoned the use of ActiveX