diff --git a/krusader/Panel/krview.cpp b/krusader/Panel/krview.cpp
index cbb1e8c..c5ad24f 100644
--- a/krusader/Panel/krview.cpp
+++ b/krusader/Panel/krview.cpp
@@ -94,6 +94,11 @@ void KrViewOperator::fileAdded(vfile *vf)
     _view->addItem(vf);
 }
 
+void KrViewOperator::fileDeleted(const QString& name)
+{
+    _view->delItem(name);
+}
+
 void KrViewOperator::fileUpdated(vfile *vf)
 {
     _view->updateItem(vf);
@@ -1045,6 +1050,7 @@ void KrView::setFiles(VfileContainer *files)
     QObject::connect(_files, SIGNAL(cleared()), op(), SLOT(cleared()));
     QObject::connect(_files, SIGNAL(addedVfile(vfile*)), op(), SLOT(fileAdded(vfile*)));
     QObject::connect(_files, SIGNAL(updatedVfile(vfile*)), op(), SLOT(fileUpdated(vfile*)));
+    QObject::connect(_files, SIGNAL(deletedVfile(const QString&)), op(), SLOT(fileDeleted(const QString&)));
 }
 
 void KrView::setFilter(KrViewProperties::FilterSpec filter, FilterSettings customFilter, bool applyToDirs)
diff --git a/krusader/Panel/krview.h b/krusader/Panel/krview.h
index 4f7927e..099366c 100644
--- a/krusader/Panel/krview.h
+++ b/krusader/Panel/krview.h
@@ -229,6 +229,7 @@ protected slots:
     void cleared();
 
     void fileAdded(vfile *vf);
+    void fileDeleted(const QString& name);
     void fileUpdated(vfile *vf);
 
 protected:
diff --git a/krusader/VFS/default_vfs.cpp b/krusader/VFS/default_vfs.cpp
index ad16bb9..650fbb8 100644
--- a/krusader/VFS/default_vfs.cpp
+++ b/krusader/VFS/default_vfs.cpp
@@ -189,7 +189,7 @@ bool default_vfs::refreshInternal(const QUrl &directory, bool showHidden)
     // start the listing job
     KIO::ListJob *job = KIO::listDir(_currentDirectory, KIO::HideProgressInfo, showHidden);
     connect(job, SIGNAL(entries(KIO::Job *, const KIO::UDSEntryList &)), this,
-            SLOT(slotAddFiles(KIO::Job *, const KIO::UDSEntryList &)));
+            SLOT(slotAddPendingFiles(KIO::Job *, const KIO::UDSEntryList &)));
     connect(job, &KIO::ListJob::redirection, this, &default_vfs::slotRedirection);
     connect(job, &KIO::ListJob::permanentRedirection, this, &default_vfs::slotRedirection);
     connect(job, SIGNAL(result(KJob*)), this, SLOT(slotListResult(KJob*)));
@@ -221,12 +221,12 @@ void default_vfs::slotListResult(KJob *job)
     }
 }
 
-void default_vfs::slotAddFiles(KIO::Job *, const KIO::UDSEntryList& entries)
+void default_vfs::slotAddPendingFiles(KIO::Job *, const KIO::UDSEntryList& entries)
 {
     for (const KIO::UDSEntry entry : entries) {
         vfile *vfile = vfs::createVFileFromKIO(entry, _currentDirectory);
         if (vfile) {
-            addVfile(vfile);
+            addPendingVfile(vfile);
         }
     }
 }
@@ -337,7 +337,7 @@ bool default_vfs::refreshLocal(const QUrl &directory) {
         if (name == "." || name == "..") continue;
 
         vfile* temp = createLocalVFile(name);
-        addVfile(temp);
+        addPendingVfile(temp);
     }
     // clean up
     QT_CLOSEDIR(dir);
diff --git a/krusader/VFS/default_vfs.h b/krusader/VFS/default_vfs.h
index d273528..d60a098 100644
--- a/krusader/VFS/default_vfs.h
+++ b/krusader/VFS/default_vfs.h
@@ -79,7 +79,7 @@ protected slots:
     /// Handle result after dir listing job is finished
     void slotListResult(KJob *job);
     /// Fill directory file list with new files from the dir lister
-    void slotAddFiles(KIO::Job *job, const KIO::UDSEntryList &entries);
+    void slotAddPendingFiles(KIO::Job *job, const KIO::UDSEntryList &entries);
     /// URL redirection signal from dir lister
     void slotRedirection(KIO::Job *job, const QUrl &url);
     // React to filesystem changes nofified by watcher
diff --git a/krusader/VFS/vfilecontainer.h b/krusader/VFS/vfilecontainer.h
index d6ce27b..d4216c9 100644
--- a/krusader/VFS/vfilecontainer.h
+++ b/krusader/VFS/vfilecontainer.h
@@ -48,6 +48,7 @@ signals:
 
     void addedVfile(vfile *vf);
     void updatedVfile(vfile *vf);
+    void deletedVfile(const QString&);
 };
 
 #endif // VFILECONTAINER_H
diff --git a/krusader/VFS/vfs.cpp b/krusader/VFS/vfs.cpp
index 3ee0bdb..b57f334 100644
--- a/krusader/VFS/vfs.cpp
+++ b/krusader/VFS/vfs.cpp
@@ -119,7 +119,6 @@ QUrl vfs::ensureTrailingSlash(const QUrl &url)
 
 bool vfs::refresh(const QUrl &directory)
 {
-
     if (_isRefreshing) {
         // NOTE: this does not happen (unless async)";
         return false;
@@ -136,30 +135,88 @@ bool vfs::refresh(const QUrl &directory)
 
     _isRefreshing = true;
 
-    vfileDict tempVfiles(_vfiles); // old vfiles are still used during refresh
-    _vfiles.clear();
     if (dirChange)
         // show an empty directory while loading the new one and clear selection
         emit cleared();
 
     const bool res = refreshInternal(toRefresh, showHiddenFiles());
-    _isRefreshing = false;
 
     if (!res) {
         // cleanup and abort
+        clear(_pendingVfiles);
+        clear(_vfiles);
+        _isRefreshing = false;
         if (!dirChange)
             emit cleared();
-        clear(tempVfiles);
         return false;
     }
 
-    emit refreshDone(dirChange);
+    // makes changes in _vfiles
+    // emit those changes
+    // also clears _pendingVfiles
+    storeAndEmitUpdates(dirChange);
 
-    clear(tempVfiles);
+    _isRefreshing = false;
 
     return true;
 }
 
+void vfs::storeAndEmitUpdates(const bool dirChange)
+{
+    int allowedNumberOfChanges = 10;
+
+    // check if the maximum incremental refresh number is not exceeded
+    int numberOfChanges = _vfiles.count() - _pendingVfiles.count();
+    if (numberOfChanges < 0)
+        numberOfChanges = -numberOfChanges;
+    if (dirChange || numberOfChanges > allowedNumberOfChanges) {
+
+        _vfiles.swap(_pendingVfiles);
+
+        // emit full refresh
+        emit refreshDone(dirChange);
+
+        clear(_pendingVfiles);
+        return;
+    }
+
+    // find and emit delete or update changes
+    for (const QString &name : QStringList(_vfiles.keys())) {
+        vfile* vf = _vfiles[name];
+        if (!vf) {
+            // this is needed when renaming a file, but why?!
+            continue;
+        }
+        vfile* newVf = _pendingVfiles.take(name);
+
+        if (!newVf) {
+
+            // the file was deleted..
+            emit deletedVfile(name);
+            delete vf;
+            _vfiles.remove(name);
+        } else {
+            if (*vf != *newVf) {
+
+                // the file was changed..
+                vf = newVf;
+                emit updatedVfile(vf);
+            }
+        }
+
+        delete newVf;
+    }
+
+    // everything left is a new file
+    for (vfile* newVf : _pendingVfiles.values()) {
+        addVfile(newVf);
+        emit addedVfile(newVf);
+    }
+
+    // clear the list of pointers in _pendingVfiles
+    _pendingVfiles.clear();
+}
+
 void vfs::mayRefresh()
 {
     if (ignoreRefresh()) {
@@ -420,7 +477,7 @@ void vfs::slotCalcStatResult(KJob *job)
 
 // ==== private ====
 
-void vfs::clear(vfileDict vfiles)
+void vfs::clear(vfileDict &vfiles)
 {
     QHashIterator<QString, vfile *> lit(vfiles);
     while (lit.hasNext()) {
diff --git a/krusader/VFS/vfs.h b/krusader/VFS/vfs.h
index 0cfe4d1..4730680 100644
--- a/krusader/VFS/vfs.h
+++ b/krusader/VFS/vfs.h
@@ -154,6 +154,7 @@ public slots:
     /// If the directory was read true is returned else false.
     // optional TODO: add an async version of this
     bool refresh(const QUrl &directory = QUrl());
+    void storeAndEmitUpdates(const bool dirChange);
     /// Notify this VFS that the current directory content may have changed.
     void mayRefresh();
 
@@ -175,7 +176,9 @@ protected:
 
     /// Returns true if showing hidden files is set in config.
     bool showHiddenFiles();
-    /// Add a new vfile to the internal dictionary (while refreshing).
+    /// Add a new vfile to the pending internal dictionary (while refreshing).
+    inline void addPendingVfile(vfile *vf) { _pendingVfiles.insert(vf->vfile_getName(), vf); }
+    /// Add a new vfile to the internal dictionary.
     inline void addVfile(vfile *vf) { _vfiles.insert(vf->vfile_getName(), vf); }
 
     /// Calculate the size of a file or directory (recursive).
@@ -212,10 +215,15 @@ private slots:
 
 private:
     /// Delete and clear vfiles.
-    void clear(vfileDict vfiles);
+    void clear(vfileDict &vfiles);
 
     vfileDict _vfiles;  // The list of files in the current dictionary
 
+    // Fresh list of files to replace _vfiles.
+    // They are used to determine "diff" between _vfiles and _pendingVfiles.
+    // The information is then used to emit selective changes to KrView.
+    vfileDict _pendingVfiles;
+
     // used in the calcSpace function
     bool *_calcKdsBusy;
     bool _calcStatBusy;
diff --git a/krusader/VFS/virt_vfs.cpp b/krusader/VFS/virt_vfs.cpp
index 4d28ad0..9a21488 100644
--- a/krusader/VFS/virt_vfs.cpp
+++ b/krusader/VFS/virt_vfs.cpp
@@ -247,7 +247,7 @@ bool virt_vfs::refreshInternal(const QUrl &directory, bool /*showHidden*/)
         if (!vf) { // remove URL from the list for a file that no longer exists
             it.remove();
         } else {
-            addVfile(vf);
+            addPendingVfile(vf);
         }
     }
 
